diff --git a/package-lock.json b/package-lock.json index f82faf934..758918abc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2446,13 +2446,6 @@ "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" - }, - "dependencies": { - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - } } }, "balanced-match": { @@ -7955,6 +7948,11 @@ "regenerate": "^1.4.2" } }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, "regenerator-transform": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", @@ -9308,6 +9306,51 @@ "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", "dev": true }, + "typescript-cached-transpile": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typescript-cached-transpile/-/typescript-cached-transpile-0.0.6.tgz", + "integrity": "sha512-bfPc7YUW0PrVkQHU0xN0ANRuxdPgoYYXtZEW6PNkH5a97/AOM+kPPxSTMZbpWA3BG1do22JUkfC60KoCKJ9VZQ==", + "dev": true, + "requires": { + "@types/node": "^12.12.7", + "fs-extra": "^8.1.0", + "tslib": "^1.10.0" + }, + "dependencies": { + "@types/node": { + "version": "12.20.37", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.37.tgz", + "integrity": "sha512-i1KGxqcvJaLQali+WuypQnXwcplhtNtjs66eNsZpp2P2FL/trJJxx/VWsM0YCL2iMoIJrbXje48lvIQAQ4p2ZA==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "uglify-js": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.2.tgz", diff --git a/package.json b/package.json index 084fcc48f..93a57f7c8 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "lintfix": "eslint '{src,tests}/**/*.{js,ts}' --fix", "docs": "rm -r ./docs || true; typedoc --gitRevision master --tsconfig ./tsconfig.build.json --out ./docs src && touch ./docs/.nojekyll", "proto-generate": "scripts/proto-generate.sh", - "polykey": "ts-node --require tsconfig-paths/register --transpile-only src/bin/polykey.ts" + "polykey": "ts-node --require tsconfig-paths/register --compiler typescript-cached-transpile --transpile-only src/bin/polykey.ts" }, "dependencies": { "@grpc/grpc-js": "1.3.7", @@ -95,6 +95,7 @@ "pako": "^1.0.11", "prompts": "^2.4.1", "readable-stream": "^3.6.0", + "resource-counter": "^1.2.4", "threads": "^1.6.5", "ts-custom-error": "^3.2.0", "utp-native": "^2.5.3", @@ -130,6 +131,7 @@ "ts-node": "^10.4.0", "tsconfig-paths": "^3.9.0", "typedoc": "^0.21.5", - "typescript": "^4.1.3" + "typescript": "^4.1.3", + "typescript-cached-transpile": "0.0.6" } } diff --git a/src/agent/GRPCClientAgent.ts b/src/agent/GRPCClientAgent.ts index 25d5432a7..ce9a22c9a 100644 --- a/src/agent/GRPCClientAgent.ts +++ b/src/agent/GRPCClientAgent.ts @@ -38,16 +38,17 @@ class GRPCClientAgent extends GRPCClient { logger?: Logger; }): Promise { logger.info(`Creating ${this.name}`); - const { client, serverCertChain } = await super.createClient({ - clientConstructor: AgentServiceClient, - nodeId, - host, - port, - tlsConfig, - proxyConfig, - timeout, - logger, - }); + const { client, serverCertChain, flowCountInterceptor } = + await super.createClient({ + clientConstructor: AgentServiceClient, + nodeId, + host, + port, + tlsConfig, + proxyConfig, + timeout, + logger, + }); const grpcClientAgent = new GRPCClientAgent({ client, nodeId, @@ -56,6 +57,7 @@ class GRPCClientAgent extends GRPCClient { tlsConfig, proxyConfig, serverCertChain, + flowCountInterceptor, logger, }); logger.info(`Created ${this.name}`); diff --git a/src/bin/agent/CommandLock.ts b/src/bin/agent/CommandLock.ts index 5c408fd8e..60a2cf141 100644 --- a/src/bin/agent/CommandLock.ts +++ b/src/bin/agent/CommandLock.ts @@ -9,7 +9,6 @@ class CommandLock extends CommandPolykey { this.description('Lock the Client and Clear the Existing Token'); this.action(async (options) => { const { default: Session } = await import('../../sessions/Session'); - // Just delete the session token const session = new Session({ sessionTokenPath: path.join( options.nodePath, @@ -18,6 +17,7 @@ class CommandLock extends CommandPolykey { fs: this.fs, logger: this.logger.getChild(Session.name), }); + // Destroy local session await session.destroy(); }); } diff --git a/src/bin/agent/CommandLockAll.ts b/src/bin/agent/CommandLockAll.ts index d0c532049..faa154072 100644 --- a/src/bin/agent/CommandLockAll.ts +++ b/src/bin/agent/CommandLockAll.ts @@ -1,8 +1,10 @@ import type PolykeyClient from '../../PolykeyClient'; +import path from 'path'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; import * as binOptions from '../utils/options'; import * as binProcessors from '../utils/processors'; +import config from '../../config'; class CommandLockAll extends CommandPolykey { constructor(...args: ConstructorParameters) { @@ -14,7 +16,9 @@ class CommandLockAll extends CommandPolykey { this.addOption(binOptions.clientPort); this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); + const { default: Session } = await import('../../sessions/Session'); const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); + const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -23,7 +27,19 @@ class CommandLockAll extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + const session = new Session({ + sessionTokenPath: path.join( + options.nodePath, + config.defaults.tokenBase, + ), + fs: this.fs, + logger: this.logger.getChild(Session.name), + }); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -35,18 +51,15 @@ class CommandLockAll extends CommandPolykey { nodePath: options.nodePath, logger: this.logger.getChild(PolykeyClient.name), }); - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const emptyMessage = new utilsPB.EmptyMessage(); await binUtils.retryAuthentication( - (auth) => grpcClient.sessionsLockAll(emptyMessage, auth), + (auth) => pkClient.grpcClient.sessionsLockAll(emptyMessage, auth), meta, ); + // Destroy local session + await session.destroy(); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/agent/CommandStart.ts b/src/bin/agent/CommandStart.ts index ce802125d..cf4f54e07 100644 --- a/src/bin/agent/CommandStart.ts +++ b/src/bin/agent/CommandStart.ts @@ -9,7 +9,7 @@ import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; import * as binProcessors from '../utils/processors'; import * as binErrors from '../errors'; -import { promise } from '../../utils'; +import { promise, dirEmpty } from '../../utils'; import config from '../../config'; class CommandStart extends CommandPolykey { @@ -33,12 +33,35 @@ class CommandStart extends CommandPolykey { options.clientPort = options.clientPort ?? config.defaults.networkConfig.clientPort; const { default: PolykeyAgent } = await import('../../PolykeyAgent'); - // Password is necessary - // If recovery code is supplied, then this is the new password - const password = await binProcessors.processPassword( - options.passwordFile, - this.fs, - ); + let password: string | undefined; + if (options.fresh) { + // If fresh, then get a new password + password = await binProcessors.processNewPassword( + options.passwordFile, + this.fs, + ); + } else if (options.recoveryCodeFile != null) { + // If recovery code is supplied, then this is the new password + password = await binProcessors.processNewPassword( + options.passwordFile, + this.fs, + ); + } else if (await dirEmpty(this.fs, options.nodePath)) { + // If the node path is empty, get a new password + password = await binProcessors.processNewPassword( + options.passwordFile, + this.fs, + ); + } else { + // Otherwise this is the existing password + // however, the code is capable of doing partial bootstrapping + // so it's possible that this is also a new password + // if the root key isn't setup + password = await binProcessors.processPassword( + options.passwordFile, + this.fs, + ); + } const recoveryCodeIn = await binProcessors.processRecoveryCode( options.recoveryCodeFile, this.fs, diff --git a/src/bin/agent/CommandStatus.ts b/src/bin/agent/CommandStatus.ts index d38921522..ea15fb6e7 100644 --- a/src/bin/agent/CommandStatus.ts +++ b/src/bin/agent/CommandStatus.ts @@ -38,6 +38,10 @@ class CommandStatus extends CommandPolykey { }), ); } else { + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); @@ -51,10 +55,6 @@ class CommandStatus extends CommandPolykey { nodePath: options.nodePath, logger: this.logger.getChild(PolykeyClient.name), }); - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); const emptyMessage = new utilsPB.EmptyMessage(); response = await binUtils.retryAuthentication( (auth) => pkClient.grpcClient.agentStatus(emptyMessage, auth), diff --git a/src/bin/agent/CommandStop.ts b/src/bin/agent/CommandStop.ts index 9c3f78111..80705dd58 100644 --- a/src/bin/agent/CommandStop.ts +++ b/src/bin/agent/CommandStop.ts @@ -34,6 +34,10 @@ class CommandStop extends CommandPolykey { } else if (statusInfo?.status === 'STARTING') { throw new binErrors.ErrorCLIStatusStarting(); } + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); // Either the statusInfo is undefined or LIVE // Either way, the connection parameters now exist let pkClient: PolykeyClient; @@ -48,14 +52,9 @@ class CommandStop extends CommandPolykey { port: clientStatus.clientPort!, logger: this.logger.getChild(PolykeyClient.name), }); - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); const emptyMessage = new utilsPB.EmptyMessage(); - const grpcClient = pkClient.grpcClient; await binUtils.retryAuthentication( - (auth) => grpcClient.agentStop(emptyMessage, auth), + (auth) => pkClient.grpcClient.agentStop(emptyMessage, auth), meta, ); this.logger.info('Stopping Agent'); diff --git a/src/bin/agent/CommandUnlock.ts b/src/bin/agent/CommandUnlock.ts index c4467804e..3215253a5 100644 --- a/src/bin/agent/CommandUnlock.ts +++ b/src/bin/agent/CommandUnlock.ts @@ -1,6 +1,3 @@ -import type { SessionToken } from '../../sessions/types'; -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -17,10 +14,7 @@ class CommandUnlock extends CommandPolykey { this.addOption(binOptions.clientPort); this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); - const sessionsPB = await import( - '../../proto/js/polykey/v1/sessions/sessions_pb' - ); - + const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -29,41 +23,29 @@ class CommandUnlock extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + 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({ - nodePath: options.nodePath, nodeId: clientOptions.nodeId, host: clientOptions.clientHost, port: clientOptions.clientPort, + nodePath: options.nodePath, logger: this.logger.getChild(PolykeyClient.name), }); - - const password = await binProcessors.processPassword( - options.passwordFile, - this.fs, + const emptyMessage = new utilsPB.EmptyMessage(); + await binUtils.retryAuthentication( + (auth) => pkClient.grpcClient.sessionsUnlock(emptyMessage, auth), + meta, ); - const grpcClient = pkClient.grpcClient; - const passwordMessage = new sessionsPB.Password(); - passwordMessage.setPassword(password); - const responseMessage = await binUtils.retryAuthentication( - (metaRetried?: Metadata) => { - return metaRetried != null - ? grpcClient.sessionsUnlock(passwordMessage, metaRetried) - : grpcClient.sessionsUnlock(passwordMessage); - }, - ); - const token: SessionToken = responseMessage.getToken() as SessionToken; - - // Write token to file - await pkClient.session.writeToken(token); - process.stdout.write('Client session started'); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/bootstrap/CommandBootstrap.ts b/src/bin/bootstrap/CommandBootstrap.ts index 93387465c..9842653c0 100644 --- a/src/bin/bootstrap/CommandBootstrap.ts +++ b/src/bin/bootstrap/CommandBootstrap.ts @@ -13,7 +13,7 @@ class CommandBootstrap extends CommandPolykey { this.addOption(binOptions.fresh); this.action(async (options) => { const bootstrapUtils = await import('../../bootstrap/utils'); - const password = await binProcessors.processPassword( + const password = await binProcessors.processNewPassword( options.passwordFile, this.fs, ); diff --git a/src/bin/identities/CommandAllow.ts b/src/bin/identities/CommandAllow.ts index ae1ba6b8a..04d0190de 100644 --- a/src/bin/identities/CommandAllow.ts +++ b/src/bin/identities/CommandAllow.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -30,7 +28,6 @@ class CommandAllow extends CommandPolykey { '../../proto/js/polykey/v1/permissions/permissions_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -39,8 +36,11 @@ class CommandAllow extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -52,26 +52,20 @@ class CommandAllow extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const setActionMessage = new permissionsPB.ActionSet(); setActionMessage.setAction(permissions); - let name: string; if (gestaltId.nodeId) { // Setting by Node const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(gestaltId.nodeId); setActionMessage.setNode(nodeMessage); - name = `${gestaltId.nodeId}`; // Trusting await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsSetByNode(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsSetByNode( + setActionMessage, + auth, + ), meta, ); } else { @@ -80,24 +74,17 @@ class CommandAllow extends CommandPolykey { providerMessage.setProviderId(gestaltId.providerId); providerMessage.setMessage(gestaltId.identityId); setActionMessage.setIdentity(providerMessage); - name = `${parsers.formatIdentityString( - gestaltId.providerId, - gestaltId.identityId, - )}`; await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsSetByIdentity(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsSetByIdentity( + setActionMessage, + auth, + ), meta, ); } - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Allowing: ${name} ${permissions}`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandAuthenticate.ts b/src/bin/identities/CommandAuthenticate.ts index 5902c76dc..dd19ace19 100644 --- a/src/bin/identities/CommandAuthenticate.ts +++ b/src/bin/identities/CommandAuthenticate.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -21,7 +19,6 @@ class CommandAuthenticate extends CommandPolykey { const identitiesPB = await import( '../../proto/js/polykey/v1/identities/identities_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +27,11 @@ class CommandAuthenticate extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,23 +43,14 @@ class CommandAuthenticate extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; - // Constructing message. const providerMessage = new identitiesPB.Provider(); providerMessage.setProviderId(providerId); providerMessage.setMessage(identityId); - // Sending message. const successMessage = await binUtils.retryAuthentication( - async (meta: Metadata) => { - const stream = grpcClient.identitiesAuthenticate( + async (auth) => { + const stream = pkClient.grpcClient.identitiesAuthenticate( providerMessage, - meta, + auth, ); const codeMessage = (await stream.next()).value; process.stdout.write( @@ -72,7 +63,6 @@ class CommandAuthenticate extends CommandPolykey { }, meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -82,7 +72,7 @@ class CommandAuthenticate extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandClaim.ts b/src/bin/identities/CommandClaim.ts index d3c4aec4b..ba5ae6241 100644 --- a/src/bin/identities/CommandClaim.ts +++ b/src/bin/identities/CommandClaim.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -21,7 +19,6 @@ class CommandClaim extends CommandPolykey { const identitiesPB = await import( '../../proto/js/polykey/v1/identities/identities_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +27,11 @@ class CommandClaim extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,27 +43,15 @@ class CommandClaim extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; - - // Constructing message. const providerMessage = new identitiesPB.Provider(); providerMessage.setProviderId(providerId); providerMessage.setMessage(identityId); - - // Sending message. await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.identitiesClaim(providerMessage, auth), + (auth) => pkClient.grpcClient.identitiesClaim(providerMessage, auth), meta, ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandDisallow.ts b/src/bin/identities/CommandDisallow.ts index 40b79379f..3f143b97d 100644 --- a/src/bin/identities/CommandDisallow.ts +++ b/src/bin/identities/CommandDisallow.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -30,7 +28,6 @@ class CommandDisallow extends CommandPolykey { '../../proto/js/polykey/v1/permissions/permissions_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -39,8 +36,11 @@ class CommandDisallow extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -52,26 +52,20 @@ class CommandDisallow extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; - let name: string; const setActionMessage = new permissionsPB.ActionSet(); setActionMessage.setAction(permissions); - if (gestaltId.nodeId) { // Setting by Node. const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(gestaltId.nodeId); setActionMessage.setNode(nodeMessage); - name = `${gestaltId.nodeId}`; // Trusting await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsUnsetByNode(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsUnsetByNode( + setActionMessage, + auth, + ), meta, ); } else { @@ -80,27 +74,18 @@ class CommandDisallow extends CommandPolykey { providerMessage.setProviderId(gestaltId.providerId); providerMessage.setMessage(gestaltId.identityId); setActionMessage.setIdentity(providerMessage); - name = `${parsers.formatIdentityString( - gestaltId.providerId, - gestaltId.identityId, - )}`; // Trusting. await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsUnsetByIdentity(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsUnsetByIdentity( + setActionMessage, + auth, + ), meta, ); } - - const action = options.action; - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Allowing: ${name} ${action}`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandDiscover.ts b/src/bin/identities/CommandDiscover.ts index 49b7ed7e9..748ba142e 100644 --- a/src/bin/identities/CommandDiscover.ts +++ b/src/bin/identities/CommandDiscover.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -28,7 +26,6 @@ class CommandDiscover extends CommandPolykey { '../../proto/js/polykey/v1/identities/identities_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -37,8 +34,11 @@ class CommandDiscover extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -50,22 +50,13 @@ class CommandDiscover extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; - let name: string; - if (gestaltId.nodeId) { // Discovery by Node. const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(gestaltId.nodeId); - name = `${gestaltId.nodeId}`; await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsDiscoveryByNode(nodeMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsDiscoveryByNode(nodeMessage, auth), meta, ); } else { @@ -73,25 +64,17 @@ class CommandDiscover extends CommandPolykey { const providerMessage = new identitiesPB.Provider(); providerMessage.setProviderId(gestaltId.providerId); providerMessage.setMessage(gestaltId.identityId); - name = `${parsers.formatIdentityString( - gestaltId.providerId, - gestaltId.identityId, - )}`; await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsDiscoveryByIdentity(providerMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsDiscoveryByIdentity( + providerMessage, + auth, + ), meta, ); } - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Starting discovery at: ${name}...`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandGet.ts b/src/bin/identities/CommandGet.ts index 958c3ddfd..ef0cfcc1d 100644 --- a/src/bin/identities/CommandGet.ts +++ b/src/bin/identities/CommandGet.ts @@ -1,6 +1,4 @@ -import type { Metadata } from '@grpc/grpc-js'; import type gestaltsPB from '../../proto/js/polykey/v1/gestalts/gestalts_pb'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -29,7 +27,6 @@ class CommandGet extends CommandPolykey { '../../proto/js/polykey/v1/identities/identities_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -38,8 +35,11 @@ class CommandGet extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -51,21 +51,14 @@ class CommandGet extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; let res: gestaltsPB.Graph; - if (gestaltId.nodeId) { // Getting from node. const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(gestaltId.nodeId); res = await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsGestaltGetByNode(nodeMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsGestaltGetByNode(nodeMessage, auth), meta, ); } else { @@ -74,14 +67,16 @@ class CommandGet extends CommandPolykey { providerMessage.setProviderId(gestaltId.providerId); providerMessage.setMessage(gestaltId.identityId); res = await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsGestaltGetByIdentity(providerMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsGestaltGetByIdentity( + providerMessage, + auth, + ), meta, ); } const gestalt = JSON.parse(res.getGestaltGraph()); let output: any = gestalt; - if (options.format !== 'json') { // Creating a list. output = []; @@ -101,7 +96,6 @@ class CommandGet extends CommandPolykey { ); } } - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -109,7 +103,7 @@ class CommandGet extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandList.ts b/src/bin/identities/CommandList.ts index 13a93aa69..ff0a353f0 100644 --- a/src/bin/identities/CommandList.ts +++ b/src/bin/identities/CommandList.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -19,7 +17,6 @@ class CommandList extends CommandPolykey { const { default: PolykeyClient } = await import('../../PolykeyClient'); const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -28,8 +25,11 @@ class CommandList extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -41,54 +41,47 @@ class CommandList extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const emptyMessage = new utilsPB.EmptyMessage(); let output: any; - const gestalts = await binUtils.retryAuthentication( - async (meta: Metadata) => { - const gestalts: Array = []; - const stream = grpcClient.gestaltsGestaltList(emptyMessage, meta); - for await (const val of stream) { - const gestalt = JSON.parse(val.getName()); - const newGestalt: any = { - permissions: [], - nodes: [], - identities: [], - }; - for (const node of Object.keys(gestalt.nodes)) { - const nodeInfo = gestalt.nodes[node]; - newGestalt.nodes.push({ id: nodeInfo.id }); - } - for (const identity of Object.keys(gestalt.identities)) { - const identityInfo = gestalt.identities[identity]; - newGestalt.identities.push({ - providerId: identityInfo.providerId, - identityId: identityInfo.identityId, - }); - } - // Getting the permissions for the gestalt. - const nodeMessage = new nodesPB.Node(); - nodeMessage.setNodeId(newGestalt.nodes[0].id); - const actionsMessage = await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsGetByNode(nodeMessage, auth), - meta, - ); - const actionList = actionsMessage.getActionList(); - if (actionList.length === 0) newGestalt.permissions = null; - else newGestalt.permissions = actionList; - gestalts.push(newGestalt); + const gestalts = await binUtils.retryAuthentication(async (auth) => { + const gestalts: Array = []; + const stream = pkClient.grpcClient.gestaltsGestaltList( + emptyMessage, + auth, + ); + for await (const val of stream) { + const gestalt = JSON.parse(val.getName()); + const newGestalt: any = { + permissions: [], + nodes: [], + identities: [], + }; + for (const node of Object.keys(gestalt.nodes)) { + const nodeInfo = gestalt.nodes[node]; + newGestalt.nodes.push({ id: nodeInfo.id }); } - return gestalts; - }, - meta, - ); - + for (const identity of Object.keys(gestalt.identities)) { + const identityInfo = gestalt.identities[identity]; + newGestalt.identities.push({ + providerId: identityInfo.providerId, + identityId: identityInfo.identityId, + }); + } + // Getting the permissions for the gestalt. + const nodeMessage = new nodesPB.Node(); + nodeMessage.setNodeId(newGestalt.nodes[0].id); + const actionsMessage = await binUtils.retryAuthentication( + (auth) => + pkClient.grpcClient.gestaltsActionsGetByNode(nodeMessage, auth), + meta, + ); + const actionList = actionsMessage.getActionList(); + if (actionList.length === 0) newGestalt.permissions = null; + else newGestalt.permissions = actionList; + gestalts.push(newGestalt); + } + return gestalts; + }, meta); output = gestalts; if (options.format !== 'json') { // Convert to a human readable list. @@ -123,7 +116,7 @@ class CommandList extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandPermissions.ts b/src/bin/identities/CommandPermissions.ts index 5985ee698..b4509efb6 100644 --- a/src/bin/identities/CommandPermissions.ts +++ b/src/bin/identities/CommandPermissions.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -26,7 +24,6 @@ class CommandPermissions extends CommandPolykey { '../../proto/js/polykey/v1/identities/identities_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -35,8 +32,11 @@ class CommandPermissions extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -48,20 +48,14 @@ class CommandPermissions extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; let actions; if (gestaltId.nodeId) { // Getting by Node. const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(gestaltId.nodeId); const res = await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsGetByNode(nodeMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsGetByNode(nodeMessage, auth), meta, ); actions = res.getActionList(); @@ -71,13 +65,15 @@ class CommandPermissions extends CommandPolykey { providerMessage.setProviderId(gestaltId.providerId); providerMessage.setMessage(gestaltId.identityId); const res = await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsGetByIdentity(providerMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsGetByIdentity( + providerMessage, + auth, + ), meta, ); actions = res.getActionList(); } - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -85,7 +81,7 @@ class CommandPermissions extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandSearch.ts b/src/bin/identities/CommandSearch.ts index 5b12c7cfc..c6bc660d1 100644 --- a/src/bin/identities/CommandSearch.ts +++ b/src/bin/identities/CommandSearch.ts @@ -1,6 +1,4 @@ -import type { Metadata } from '@grpc/grpc-js'; import type { ProviderId, IdentityId } from '../../identities/types'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -25,7 +23,6 @@ class CommandSearch extends CommandPolykey { const identitiesPB = await import( '../../proto/js/polykey/v1/identities/identities_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -34,8 +31,11 @@ class CommandSearch extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -47,21 +47,13 @@ class CommandSearch extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const providerMessage = new identitiesPB.Provider(); providerMessage.setProviderId(providerId); const res = await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.identitiesInfoGet(providerMessage, auth), + (auth) => + pkClient.grpcClient.identitiesInfoGet(providerMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -74,7 +66,7 @@ class CommandSearch extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandTrust.ts b/src/bin/identities/CommandTrust.ts index b19142c8b..8e4f8d57f 100644 --- a/src/bin/identities/CommandTrust.ts +++ b/src/bin/identities/CommandTrust.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -29,7 +27,6 @@ class CommandTrust extends CommandPolykey { '../../proto/js/polykey/v1/permissions/permissions_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -38,8 +35,11 @@ class CommandTrust extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -51,26 +51,20 @@ class CommandTrust extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const action = 'notify'; const setActionMessage = new permissionsPB.ActionSet(); setActionMessage.setAction(action); - let name: string; - if (gestaltId.nodeId) { // Setting by Node. const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(gestaltId.nodeId); setActionMessage.setNode(nodeMessage); - name = `${gestaltId.nodeId}`; await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsSetByNode(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsSetByNode( + setActionMessage, + auth, + ), meta, ); } else { @@ -79,25 +73,17 @@ class CommandTrust extends CommandPolykey { providerMessage.setProviderId(gestaltId.providerId!); providerMessage.setMessage(gestaltId.identityId!); setActionMessage.setIdentity(providerMessage); - name = `${parsers.formatIdentityString( - gestaltId.providerId, - gestaltId.identityId, - )}`; await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsSetByIdentity(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsSetByIdentity( + setActionMessage, + auth, + ), meta, ); } - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Trusting: ${name}`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/identities/CommandUntrust.ts b/src/bin/identities/CommandUntrust.ts index 79b4c03aa..22e331203 100644 --- a/src/bin/identities/CommandUntrust.ts +++ b/src/bin/identities/CommandUntrust.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binOptions from '../utils/options'; @@ -29,7 +27,6 @@ class CommandUntrust extends CommandPolykey { '../../proto/js/polykey/v1/permissions/permissions_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -38,8 +35,11 @@ class CommandUntrust extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -51,26 +51,20 @@ class CommandUntrust extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const action = 'notify'; const setActionMessage = new permissionsPB.ActionSet(); setActionMessage.setAction(action); - let name: string; - if (gestaltId.nodeId) { // Setting by Node. const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(gestaltId.nodeId); setActionMessage.setNode(nodeMessage); - name = `${gestaltId.nodeId}`; await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsUnsetByNode(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsUnsetByNode( + setActionMessage, + auth, + ), meta, ); } else { @@ -79,25 +73,17 @@ class CommandUntrust extends CommandPolykey { providerMessage.setProviderId(gestaltId.providerId!); providerMessage.setMessage(gestaltId.identityId!); setActionMessage.setIdentity(providerMessage); - name = `${parsers.formatIdentityString( - gestaltId.providerId, - gestaltId.identityId, - )}`; await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.gestaltsActionsUnsetByIdentity(setActionMessage, auth), + (auth) => + pkClient.grpcClient.gestaltsActionsUnsetByIdentity( + setActionMessage, + auth, + ), meta, ); } - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`untrusting: ${name}`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandCert.ts b/src/bin/keys/CommandCert.ts index a10bc47e0..f16937a48 100644 --- a/src/bin/keys/CommandCert.ts +++ b/src/bin/keys/CommandCert.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -17,7 +15,6 @@ class CommandCert extends CommandPolykey { this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -26,8 +23,11 @@ class CommandCert extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -39,19 +39,11 @@ class CommandCert extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const emptyMessage = new utilsPB.EmptyMessage(); const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysCertsGet(emptyMessage, auth), + (auth) => pkClient.grpcClient.keysCertsGet(emptyMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -59,7 +51,7 @@ class CommandCert extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandCertchain.ts b/src/bin/keys/CommandCertchain.ts index 4aedc0fde..a3065a842 100644 --- a/src/bin/keys/CommandCertchain.ts +++ b/src/bin/keys/CommandCertchain.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -17,7 +15,6 @@ class CommandsCertchain extends CommandPolykey { this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -26,8 +23,11 @@ class CommandsCertchain extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -39,26 +39,18 @@ class CommandsCertchain extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const emptyMessage = new utilsPB.EmptyMessage(); - const data = await binUtils.retryAuthentication( - async (meta: Metadata) => { - const data: Array = []; - const stream = grpcClient.keysCertsChainGet(emptyMessage, meta); - for await (const cert of stream) { - data.push(`Certificate:\t\t${cert.getCert()}`); - } - return data; - }, - meta, - ); - + const data = await binUtils.retryAuthentication(async (auth) => { + const data: Array = []; + const stream = pkClient.grpcClient.keysCertsChainGet( + emptyMessage, + auth, + ); + for await (const cert of stream) { + data.push(`Certificate:\t\t${cert.getCert()}`); + } + return data; + }, meta); process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -66,7 +58,7 @@ class CommandsCertchain extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandDecrypt.ts b/src/bin/keys/CommandDecrypt.ts index 7410e9486..dec93bd68 100644 --- a/src/bin/keys/CommandDecrypt.ts +++ b/src/bin/keys/CommandDecrypt.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import * as binErrors from '../errors'; import CommandPolykey from '../CommandPolykey'; @@ -22,7 +20,6 @@ class CommandDecrypt extends CommandPolykey { this.action(async (filePath, options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const keysPB = await import('../../proto/js/polykey/v1/keys/keys_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandDecrypt extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,13 +44,6 @@ class CommandDecrypt extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const cryptoMessage = new keysPB.Crypto(); let cipherText: string; try { @@ -65,13 +58,11 @@ class CommandDecrypt extends CommandPolykey { path: e.path, }); } - cryptoMessage.setData(cipherText); const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysDecrypt(cryptoMessage, auth), + (auth) => pkClient.grpcClient.keysDecrypt(cryptoMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -79,7 +70,7 @@ class CommandDecrypt extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandEncrypt.ts b/src/bin/keys/CommandEncrypt.ts index 02ad669bf..7488a0193 100644 --- a/src/bin/keys/CommandEncrypt.ts +++ b/src/bin/keys/CommandEncrypt.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import * as binErrors from '../errors'; import CommandPolykey from '../CommandPolykey'; @@ -22,7 +20,6 @@ class CommandEncypt extends CommandPolykey { this.action(async (filePath, options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const keysPB = await import('../../proto/js/polykey/v1/keys/keys_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandEncypt extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,15 +44,7 @@ class CommandEncypt extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const cryptoMessage = new keysPB.Crypto(); - let plainText: string; try { plainText = await this.fs.promises.readFile(filePath, { @@ -66,13 +58,11 @@ class CommandEncypt extends CommandPolykey { path: e.path, }); } - cryptoMessage.setData(plainText); const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysEncrypt(cryptoMessage, auth), + (auth) => pkClient.grpcClient.keysEncrypt(cryptoMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -80,7 +70,7 @@ class CommandEncypt extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandPassword.ts b/src/bin/keys/CommandPassword.ts index 3532f8fa5..b56da6572 100644 --- a/src/bin/keys/CommandPassword.ts +++ b/src/bin/keys/CommandPassword.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -11,19 +9,15 @@ class CommandPassword extends CommandPolykey { super(...args); this.name('password'); this.description('Change the Password for the Root Keypair'); - this.argument( - '', - 'Path to the password for the new root key', - ); this.addOption(binOptions.nodeId); this.addOption(binOptions.clientHost); this.addOption(binOptions.clientPort); - this.action(async (passwordPath, options) => { + this.addOption(binOptions.passwordNewFile); + this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const sessionsPB = await import( '../../proto/js/polykey/v1/sessions/sessions_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -32,8 +26,16 @@ class CommandPassword extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + const passwordNew = await binProcessors.processNewPassword( + options.passwordNewFile, + this.fs, + true, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -45,34 +47,15 @@ class CommandPassword extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const passwordMessage = new sessionsPB.Password(); - - const password = await binProcessors.processPassword( - passwordPath, - this.fs, - ); - passwordMessage.setPassword(password); - + passwordMessage.setPassword(passwordNew); await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.keysPasswordChange(passwordMessage, auth), + (auth) => + pkClient.grpcClient.keysPasswordChange(passwordMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Password to root keypair changed`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandRenew.ts b/src/bin/keys/CommandRenew.ts index d3472f51e..d7d1d2918 100644 --- a/src/bin/keys/CommandRenew.ts +++ b/src/bin/keys/CommandRenew.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -11,17 +9,13 @@ class CommandRenew extends CommandPolykey { super(...args); this.name('renew'); this.description('Renew the Root Keypair'); - this.argument( - '', - 'Path to the password for the new root key', - ); this.addOption(binOptions.nodeId); this.addOption(binOptions.clientHost); this.addOption(binOptions.clientPort); - this.action(async (passwordPath, options) => { + this.addOption(binOptions.passwordNewFile); + this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const keysPB = await import('../../proto/js/polykey/v1/keys/keys_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +24,16 @@ class CommandRenew extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + const passwordNew = await binProcessors.processNewPassword( + options.passwordNewFile, + this.fs, + true, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,33 +45,14 @@ class CommandRenew extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const keyMessage = new keysPB.Key(); - - const password = await binProcessors.processPassword( - passwordPath, - this.fs, - ); - keyMessage.setName(password); - + keyMessage.setName(passwordNew); await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysKeyPairRenew(keyMessage, auth), + (auth) => pkClient.grpcClient.keysKeyPairRenew(keyMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Renewed root keypair successfully`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandReset.ts b/src/bin/keys/CommandReset.ts index d8b4b0f47..3e47974a1 100644 --- a/src/bin/keys/CommandReset.ts +++ b/src/bin/keys/CommandReset.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -11,17 +9,13 @@ class CommandReset extends CommandPolykey { super(...args); this.name('reset'); this.description('Reset the Root Keypair'); - this.argument( - '', - 'Path to the password for the new root key', - ); this.addOption(binOptions.nodeId); this.addOption(binOptions.clientHost); this.addOption(binOptions.clientPort); - this.action(async (passwordPath, options) => { + this.addOption(binOptions.passwordNewFile); + this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const keysPB = await import('../../proto/js/polykey/v1/keys/keys_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +24,16 @@ class CommandReset extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + const passwordNew = await binProcessors.processNewPassword( + options.passwordNewFile, + this.fs, + true, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,33 +45,14 @@ class CommandReset extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const keyMessage = new keysPB.Key(); - - const password = await binProcessors.processPassword( - passwordPath, - this.fs, - ); - keyMessage.setName(password); - + keyMessage.setName(passwordNew); await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysKeyPairReset(keyMessage, auth), + (auth) => pkClient.grpcClient.keysKeyPairReset(keyMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Reset root keypair successfully`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandRoot.ts b/src/bin/keys/CommandRoot.ts index 9af8b359c..8303871e8 100644 --- a/src/bin/keys/CommandRoot.ts +++ b/src/bin/keys/CommandRoot.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -18,7 +16,6 @@ class CommandRoot extends CommandPolykey { this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -27,8 +24,11 @@ class CommandRoot extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -40,26 +40,17 @@ class CommandRoot extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const emptyMessage = new utilsPB.EmptyMessage(); - const keyPair = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysKeyPairRoot(emptyMessage, auth), + (auth) => pkClient.grpcClient.keysKeyPairRoot(emptyMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', data: [`public key:\t\t${keyPair.getPublic()}...`], }), ); - if (options.privateKey) { process.stdout.write( binUtils.outputFormatter({ @@ -69,7 +60,7 @@ class CommandRoot extends CommandPolykey { ); } } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandSign.ts b/src/bin/keys/CommandSign.ts index fd5e4ab68..bf195e9dc 100644 --- a/src/bin/keys/CommandSign.ts +++ b/src/bin/keys/CommandSign.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import * as binErrors from '../errors'; import CommandPolykey from '../CommandPolykey'; @@ -22,7 +20,6 @@ class CommandSign extends CommandPolykey { this.action(async (filePath, options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const keysPB = await import('../../proto/js/polykey/v1/keys/keys_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandSign extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,14 +44,7 @@ class CommandSign extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const cryptoMessage = new keysPB.Crypto(); - let data: string; try { data = await this.fs.promises.readFile(filePath, { @@ -66,12 +59,10 @@ class CommandSign extends CommandPolykey { }); } cryptoMessage.setData(data); - const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysSign(cryptoMessage, auth), + (auth) => pkClient.grpcClient.keysSign(cryptoMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -79,7 +70,7 @@ class CommandSign extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/keys/CommandVerify.ts b/src/bin/keys/CommandVerify.ts index 4569a274f..88e3da00c 100644 --- a/src/bin/keys/CommandVerify.ts +++ b/src/bin/keys/CommandVerify.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import * as binErrors from '../errors'; import CommandPolykey from '../CommandPolykey'; @@ -26,7 +24,6 @@ class CommandVerify extends CommandPolykey { this.action(async (filePath, signaturePath, options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const keysPB = await import('../../proto/js/polykey/v1/keys/keys_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -35,8 +32,11 @@ class CommandVerify extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -48,14 +48,7 @@ class CommandVerify extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const cryptoMessage = new keysPB.Crypto(); - let data: string; let signature: string; try { @@ -73,15 +66,12 @@ class CommandVerify extends CommandPolykey { path: e.path, }); } - cryptoMessage.setData(data); cryptoMessage.setSignature(signature); - const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.keysVerify(cryptoMessage, auth), + (auth) => pkClient.grpcClient.keysVerify(cryptoMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -89,7 +79,7 @@ class CommandVerify extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/nodes/CommandAdd.ts b/src/bin/nodes/CommandAdd.ts index b079783d3..6cbdc0115 100644 --- a/src/bin/nodes/CommandAdd.ts +++ b/src/bin/nodes/CommandAdd.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils/utils'; @@ -20,7 +18,6 @@ class CommandAdd extends CommandPolykey { this.action(async (nodeId, host, port, options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -29,8 +26,11 @@ class CommandAdd extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -42,31 +42,17 @@ class CommandAdd extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const nodeAddressMessage = new nodesPB.NodeAddress(); nodeAddressMessage.setNodeId(nodeId); nodeAddressMessage.setAddress( new nodesPB.Address().setHost(host).setPort(port), ); - await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.nodesAdd(nodeAddressMessage, auth), + (auth) => pkClient.grpcClient.nodesAdd(nodeAddressMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: ['Added node'], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/nodes/CommandClaim.ts b/src/bin/nodes/CommandClaim.ts index fd0e783ef..ca7408aee 100644 --- a/src/bin/nodes/CommandClaim.ts +++ b/src/bin/nodes/CommandClaim.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -22,7 +20,6 @@ class CommandClaim extends CommandPolykey { this.action(async (nodeId, options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandClaim extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,12 +44,6 @@ class CommandClaim extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const nodeClaimMessage = new nodesPB.Claim(); nodeClaimMessage.setNodeId(nodeId); if (options.forceInvite) { @@ -57,13 +51,11 @@ class CommandClaim extends CommandPolykey { } else { nodeClaimMessage.setForceInvite(false); } - const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.nodesClaim(nodeClaimMessage, auth), + (auth) => pkClient.grpcClient.nodesClaim(nodeClaimMessage, auth), meta, ); const claimed = response.getSuccess(); - if (claimed) { process.stdout.write( binUtils.outputFormatter({ @@ -84,7 +76,7 @@ class CommandClaim extends CommandPolykey { ); } } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/nodes/CommandFind.ts b/src/bin/nodes/CommandFind.ts index 68f0e22fe..61d7c3cd5 100644 --- a/src/bin/nodes/CommandFind.ts +++ b/src/bin/nodes/CommandFind.ts @@ -1,5 +1,4 @@ import type { Host, Port } from '../../network/types'; -import type { Metadata } from '@grpc/grpc-js'; import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; @@ -22,7 +21,6 @@ class CommandFind extends CommandPolykey { const networkUtils = await import('../../network/utils'); const CLIErrors = await import('../errors'); const nodesErrors = await import('../../nodes/errors'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +29,11 @@ class CommandFind extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,12 +45,6 @@ class CommandFind extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(nodeId); const result = { @@ -61,10 +56,9 @@ class CommandFind extends CommandPolykey { }; try { const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.nodesFind(nodeMessage, auth), + (auth) => pkClient.grpcClient.nodesFind(nodeMessage, auth), meta, ); - result.success = true; result.id = response.getNodeId(); result.host = response.getAddress()!.getHost(); @@ -83,10 +77,8 @@ class CommandFind extends CommandPolykey { result.port = 0; result.message = `Failed to find node ${result.id}`; } - let output: any = result; if (options.format === 'human') output = [result.message]; - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -97,7 +89,7 @@ class CommandFind extends CommandPolykey { if (!result.success) throw new CLIErrors.ErrorNodeFindFailed(result.message); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/nodes/CommandPing.ts b/src/bin/nodes/CommandPing.ts index 8d32f339f..387abaca4 100644 --- a/src/bin/nodes/CommandPing.ts +++ b/src/bin/nodes/CommandPing.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -20,7 +18,6 @@ class CommandPing extends CommandPolykey { const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); const CLIErrors = await import('../errors'); const nodesErrors = await import('../../nodes/errors'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -29,8 +26,11 @@ class CommandPing extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -42,19 +42,13 @@ class CommandPing extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const nodeMessage = new nodesPB.Node(); nodeMessage.setNodeId(nodeId); let statusMessage; let error; try { statusMessage = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.nodesPing(nodeMessage, auth), + (auth) => pkClient.grpcClient.nodesPing(nodeMessage, auth), meta, ); } catch (err) { @@ -66,28 +60,23 @@ class CommandPing extends CommandPolykey { throw err; } } - const status = { success: false, message: '' }; status.success = statusMessage ? statusMessage.getSuccess() : false; if (!status.success && !error) error = new CLIErrors.ErrorNodePingFailed('No response received'); - if (status.success) status.message = 'Node is Active.'; else status.message = error.message; - const output: any = options.format === 'json' ? status : [status.message]; - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', data: output, }), ); - if (error != null) throw error; } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/notifications/CommandClear.ts b/src/bin/notifications/CommandClear.ts index 563a5ccb1..a149f88cb 100644 --- a/src/bin/notifications/CommandClear.ts +++ b/src/bin/notifications/CommandClear.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -17,7 +15,6 @@ class CommandClear extends CommandPolykey { this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -26,8 +23,11 @@ class CommandClear extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -39,29 +39,13 @@ class CommandClear extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const emptyMessage = new utilsPB.EmptyMessage(); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.notificationsClear(emptyMessage, auth), + (auth) => pkClient.grpcClient.notificationsClear(emptyMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Successsfully cleared all notifications`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/notifications/CommandRead.ts b/src/bin/notifications/CommandRead.ts index b3d174f60..2735a5154 100644 --- a/src/bin/notifications/CommandRead.ts +++ b/src/bin/notifications/CommandRead.ts @@ -1,5 +1,4 @@ import type { Notification } from '../../notifications/types'; -import type { Metadata } from '@grpc/grpc-js'; import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; @@ -35,7 +34,6 @@ class CommandRead extends CommandPolykey { '../../proto/js/polykey/v1/notifications/notifications_pb' ); const notificationsUtils = await import('../../notifications/utils'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -44,8 +42,11 @@ class CommandRead extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -57,14 +58,7 @@ class CommandRead extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const notificationsReadMessage = new notificationsPB.Read(); - if (options.unread) { notificationsReadMessage.setUnread(true); } else { @@ -72,13 +66,14 @@ class CommandRead extends CommandPolykey { } notificationsReadMessage.setNumber(options.number); notificationsReadMessage.setOrder(options.order); - const response = await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.notificationsRead(notificationsReadMessage, auth), + (auth) => + pkClient.grpcClient.notificationsRead( + notificationsReadMessage, + auth, + ), meta, ); - const notificationMessages = response.getNotificationList(); const notifications: Array = []; for (const message of notificationMessages) { @@ -111,7 +106,6 @@ class CommandRead extends CommandPolykey { break; } } - const notification = { data: data, senderId: message.getSenderId(), @@ -121,7 +115,6 @@ class CommandRead extends CommandPolykey { notificationsUtils.validateNotification(notification), ); } - if (notifications.length === 0) { process.stdout.write( binUtils.outputFormatter({ @@ -167,7 +160,7 @@ class CommandRead extends CommandPolykey { ); } } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/notifications/CommandSend.ts b/src/bin/notifications/CommandSend.ts index 0375c0100..40bc72104 100644 --- a/src/bin/notifications/CommandSend.ts +++ b/src/bin/notifications/CommandSend.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -21,7 +19,6 @@ class CommandSend extends CommandPolykey { const notificationsPB = await import( '../../proto/js/polykey/v1/notifications/notifications_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +27,11 @@ class CommandSend extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,36 +43,21 @@ class CommandSend extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const notificationsSendMessage = new notificationsPB.Send(); const generalMessage = new notificationsPB.General(); generalMessage.setMessage(message); notificationsSendMessage.setReceiverId(node); notificationsSendMessage.setData(generalMessage); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.notificationsSend(notificationsSendMessage, auth), + (auth) => + pkClient.grpcClient.notificationsSend( + notificationsSendMessage, + auth, + ), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Successsfully sent notification: "${notificationsSendMessage - .getData() - ?.getMessage()}" to Keynode with ID: ${notificationsSendMessage.getReceiverId()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandCreate.ts b/src/bin/secrets/CommandCreate.ts index 1a6a08d3c..b0d9a7d0d 100644 --- a/src/bin/secrets/CommandCreate.ts +++ b/src/bin/secrets/CommandCreate.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import * as binErrors from '../errors'; import CommandPolykey from '../CommandPolykey'; @@ -33,7 +31,6 @@ class CommandCreate extends CommandPolykey { const secretsPB = await import( '../../proto/js/polykey/v1/secrets/secrets_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -42,8 +39,11 @@ class CommandCreate extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -55,19 +55,11 @@ class CommandCreate extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const secretMessage = new secretsPB.Secret(); const vaultMessage = new vaultsPB.Vault(); secretMessage.setVault(vaultMessage); vaultMessage.setNameOrId(secretPath[0]); secretMessage.setSecretName(secretPath[1]); - let content: Buffer; try { content = await this.fs.promises.readFile(directoryPath); @@ -80,22 +72,12 @@ class CommandCreate extends CommandPolykey { }); } secretMessage.setSecretContent(content); - await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.vaultsSecretsNew(secretMessage, auth), + (auth) => pkClient.grpcClient.vaultsSecretsNew(secretMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Secret: ${secretMessage.getSecretName()} successfully created in vault: ${vaultMessage.getNameOrId()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandDelete.ts b/src/bin/secrets/CommandDelete.ts index b987fe8aa..300879931 100644 --- a/src/bin/secrets/CommandDelete.ts +++ b/src/bin/secrets/CommandDelete.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -29,7 +27,6 @@ class CommandDelete extends CommandPolykey { const secretsPB = await import( '../../proto/js/polykey/v1/secrets/secrets_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -38,8 +35,11 @@ class CommandDelete extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -51,34 +51,18 @@ class CommandDelete extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const secretMessage = new secretsPB.Secret(); vaultMessage.setNameOrId(secretPath[0]); secretMessage.setVault(vaultMessage); secretMessage.setSecretName(secretPath[1]); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsSecretsDelete(secretMessage, auth), + (auth) => + pkClient.grpcClient.vaultsSecretsDelete(secretMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Secret: ${secretMessage.getSecretName()} in vault: ${vaultMessage.getNameOrId()} successfully deleted`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandDir.ts b/src/bin/secrets/CommandDir.ts index 1c5b93868..813ab7aab 100644 --- a/src/bin/secrets/CommandDir.ts +++ b/src/bin/secrets/CommandDir.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -27,7 +25,6 @@ class CommandDir extends CommandPolykey { const secretsPB = await import( '../../proto/js/polykey/v1/secrets/secrets_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -36,8 +33,11 @@ class CommandDir extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -49,34 +49,21 @@ class CommandDir extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const secretDirectoryMessage = new secretsPB.Directory(); const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(vaultName); secretDirectoryMessage.setVault(vaultMessage); secretDirectoryMessage.setSecretDirectory(directoryPath); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsSecretsNewDir(secretDirectoryMessage, auth), + (auth) => + pkClient.grpcClient.vaultsSecretsNewDir( + secretDirectoryMessage, + auth, + ), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Secret directory added to vault: ${secretDirectoryMessage.getSecretDirectory()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandEdit.ts b/src/bin/secrets/CommandEdit.ts index 2d1bdda26..f3d005810 100644 --- a/src/bin/secrets/CommandEdit.ts +++ b/src/bin/secrets/CommandEdit.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import * as binErrors from '../errors'; import CommandPolykey from '../CommandPolykey'; @@ -31,7 +29,6 @@ class CommandEdit extends CommandPolykey { const secretsPB = await import( '../../proto/js/polykey/v1/secrets/secrets_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -40,8 +37,11 @@ class CommandEdit extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -53,35 +53,22 @@ class CommandEdit extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const secretMessage = new secretsPB.Secret(); const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(secretPath[0]); secretMessage.setVault(vaultMessage); secretMessage.setSecretName(secretPath[1]); - const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.vaultsSecretsGet(secretMessage, auth), + (auth) => pkClient.grpcClient.vaultsSecretsGet(secretMessage, auth), meta, ); - const secretContent = response.getSecretName(); - // Linux const tmpDir = `${os.tmpdir}/pksecret`; await this.fs.promises.mkdir(tmpDir); const tmpFile = `${tmpDir}/pkSecretFile`; - await this.fs.promises.writeFile(tmpFile, secretContent); - execSync(`$EDITOR \"${tmpFile}\"`, { stdio: 'inherit' }); - let content: Buffer; try { content = await this.fs.promises.readFile(tmpFile); @@ -93,26 +80,14 @@ class CommandEdit extends CommandPolykey { path: e.path, }); } - secretMessage.setVault(vaultMessage); secretMessage.setSecretContent(content); - await grpcClient.vaultsSecretsEdit(secretMessage); - + await pkClient.grpcClient.vaultsSecretsEdit(secretMessage); await this.fs.promises.rmdir(tmpDir, { recursive: true }); - // Windows // TODO: complete windows impl - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Edited secret: ${vaultMessage.getNameOrId()} in vault: ${vaultMessage.getNameOrId()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandGet.ts b/src/bin/secrets/CommandGet.ts index 21e412643..764a0fb91 100644 --- a/src/bin/secrets/CommandGet.ts +++ b/src/bin/secrets/CommandGet.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -32,7 +30,6 @@ class CommandGet extends CommandPolykey { const secretsPB = await import( '../../proto/js/polykey/v1/secrets/secrets_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -41,8 +38,11 @@ class CommandGet extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -54,24 +54,16 @@ class CommandGet extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const isEnv: boolean = options.env ?? false; const secretMessage = new secretsPB.Secret(); const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(secretPath[0]); secretMessage.setVault(vaultMessage); secretMessage.setSecretName(secretPath[1]); - const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.vaultsSecretsGet(secretMessage, auth), + (auth) => pkClient.grpcClient.vaultsSecretsGet(secretMessage, auth), meta, ); - if (isEnv) { process.stdout.write( binUtils.outputFormatter({ @@ -95,7 +87,7 @@ class CommandGet extends CommandPolykey { ); } } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandList.ts b/src/bin/secrets/CommandList.ts index f43448e6d..c792a617c 100644 --- a/src/bin/secrets/CommandList.ts +++ b/src/bin/secrets/CommandList.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -21,7 +19,6 @@ class CommandList extends CommandPolykey { const vaultsPB = await import( '../../proto/js/polykey/v1/vaults/vaults_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +27,11 @@ class CommandList extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,26 +43,19 @@ class CommandList extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(vaultName); - - const data = await binUtils.retryAuthentication( - async (meta: Metadata) => { - const data: Array = []; - const stream = grpcClient.vaultsSecretsList(vaultMessage, meta); - for await (const secret of stream) { - data.push(`${secret.getSecretName()}`); - } - return data; - }, - meta, - ); + const data = await binUtils.retryAuthentication(async (auth) => { + const data: Array = []; + const stream = pkClient.grpcClient.vaultsSecretsList( + vaultMessage, + auth, + ); + for await (const secret of stream) { + data.push(`${secret.getSecretName()}`); + } + return data; + }, meta); process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -70,7 +63,7 @@ class CommandList extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandMkdir.ts b/src/bin/secrets/CommandMkdir.ts index 9df108740..bba9e0db9 100644 --- a/src/bin/secrets/CommandMkdir.ts +++ b/src/bin/secrets/CommandMkdir.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -26,7 +24,6 @@ class CommandMkdir extends CommandPolykey { const vaultsPB = await import( '../../proto/js/polykey/v1/vaults/vaults_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -35,8 +32,11 @@ class CommandMkdir extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -48,35 +48,19 @@ class CommandMkdir extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMkdirMessage = new vaultsPB.Mkdir(); const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(secretPath[0]); vaultMkdirMessage.setVault(vaultMessage); vaultMkdirMessage.setDirName(secretPath[1]); vaultMkdirMessage.setRecursive(options.recursive); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsSecretsMkdir(vaultMkdirMessage, auth), + (auth) => + pkClient.grpcClient.vaultsSecretsMkdir(vaultMkdirMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Directory: ${vaultMkdirMessage.getDirName()} created inside vault: ${vaultMessage.getNameOrId()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandRename.ts b/src/bin/secrets/CommandRename.ts index 2a0a33713..9717b1c84 100644 --- a/src/bin/secrets/CommandRename.ts +++ b/src/bin/secrets/CommandRename.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -29,7 +27,6 @@ class CommandRename extends CommandPolykey { const secretsPB = await import( '../../proto/js/polykey/v1/secrets/secrets_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -38,8 +35,11 @@ class CommandRename extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -51,12 +51,6 @@ class CommandRename extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const secretMessage = new secretsPB.Secret(); const secretRenameMessage = new secretsPB.Rename(); @@ -65,23 +59,13 @@ class CommandRename extends CommandPolykey { vaultMessage.setNameOrId(secretPath[0]); secretMessage.setSecretName(secretPath[1]); secretRenameMessage.setNewName(newSecretName); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsSecretsRename(secretRenameMessage, auth), + (auth) => + pkClient.grpcClient.vaultsSecretsRename(secretRenameMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Renamed secret: ${secretMessage.getSecretName()} in vault: ${vaultMessage.getNameOrId()} to ${secretRenameMessage.getNewName()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/secrets/CommandUpdate.ts b/src/bin/secrets/CommandUpdate.ts index ef1df6806..941006aed 100644 --- a/src/bin/secrets/CommandUpdate.ts +++ b/src/bin/secrets/CommandUpdate.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import * as binErrors from '../errors'; import CommandPolykey from '../CommandPolykey'; @@ -33,7 +31,6 @@ class CommandUpdate extends CommandPolykey { const secretsPB = await import( '../../proto/js/polykey/v1/secrets/secrets_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -42,8 +39,11 @@ class CommandUpdate extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -55,18 +55,11 @@ class CommandUpdate extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const secretMessage = new secretsPB.Secret(); secretMessage.setVault(vaultMessage); vaultMessage.setNameOrId(secretPath[0]); secretMessage.setSecretName(secretPath[1]); - let content: Buffer; try { content = await this.fs.promises.readFile(directoryPath); @@ -79,23 +72,12 @@ class CommandUpdate extends CommandPolykey { }); } secretMessage.setSecretContent(content); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsSecretsEdit(secretMessage, auth), + (auth) => pkClient.grpcClient.vaultsSecretsEdit(secretMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Updated secret: ${secretMessage.getSecretName()} in vault: ${vaultMessage.getNameOrId()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/utils/options.ts b/src/bin/utils/options.ts index 56d350432..2dc3fed43 100644 --- a/src/bin/utils/options.ts +++ b/src/bin/utils/options.ts @@ -88,6 +88,11 @@ const passwordFile = new commander.Option( 'Path to Password', ); +const passwordNewFile = new commander.Option( + '-pnf, --password-new-file ', + 'Path to new Password', +); + const recoveryCodeFile = new commander.Option( '-rcf, --recovery-code-file ', 'Path to Recovery Code', @@ -123,8 +128,9 @@ export { clientPort, ingressHost, ingressPort, - recoveryCodeFile, passwordFile, + passwordNewFile, + recoveryCodeFile, background, backgroundOutFile, backgroundErrFile, diff --git a/src/bin/utils/processors.ts b/src/bin/utils/processors.ts index 1b6e5ba4b..9d3353539 100644 --- a/src/bin/utils/processors.ts +++ b/src/bin/utils/processors.ts @@ -19,21 +19,58 @@ import { Status } from '../../status'; import config from '../../config'; /** - * Prompts for password + * Prompts for existing password * This masks SIGINT handling * When SIGINT is received this will return undefined */ async function promptPassword(): Promise { - const response = await prompts({ - type: 'password', + const { password } = await prompts({ name: 'password', - message: 'Please enter your password', + type: 'password', + message: 'Please enter the password', }); - return response.password; + return password; +} + +/** + * Prompts for new password + * This masks SIGINT handling + * When SIGINT is received this will return undefined + */ +async function promptNewPassword(): Promise { + let password: string | undefined; + while (true) { + ({ password } = await prompts({ + name: 'password', + type: 'password', + message: 'Enter new password', + })); + // If undefined, then SIGINT was sent + // Break the loop and return undefined password + if (password == null) { + break; + } + const { passwordConfirm } = await prompts({ + name: 'passwordConfirm', + type: 'password', + message: 'Confirm new password', + }); + // If undefined, then SIGINT was sent + // Break the loop and return undefined password + if (passwordConfirm == null) { + break; + } + if (password === passwordConfirm) { + break; + } + // Interactive message + process.stderr.write('Passwords do not match!\n'); + } + return password; } /** - * Processes password + * Processes existing password * Use this when password is necessary * Order of operations are: * 1. Reads --password-file @@ -68,6 +105,48 @@ async function processPassword( return password; } +/** + * Processes new password + * Use this when a new password is necessary + * Order of operations are: + * 1. Reads --password-new-file + * 2. Reads PK_PASSWORD + * 3. Prompts and confirms password + * If processNewPassword is used when an existing password is needed + * for authentication, then the existing boolean should be set to true + * This ensures that this call does not read `PK_PASSWORD` + * This may return an empty string + */ +async function processNewPassword( + passwordNewFile?: string, + fs: FileSystem = require('fs'), + existing: boolean = false, +): Promise { + let passwordNew: string | undefined; + if (passwordNewFile != null) { + try { + passwordNew = ( + await fs.promises.readFile(passwordNewFile, 'utf-8') + ).trim(); + } catch (e) { + throw new binErrors.ErrorCLIPasswordFileRead(e.message, { + errno: e.errno, + syscall: e.syscall, + code: e.code, + path: e.path, + }); + } + } else if (!existing && typeof process.env['PK_PASSWORD'] === 'string') { + passwordNew = process.env['PK_PASSWORD']; + } else { + passwordNew = await promptNewPassword(); + if (passwordNew === undefined) { + throw new binErrors.ErrorCLIPasswordMissing(); + } + } + return passwordNew; +} + /** * Process recovery code * Order of operations are: @@ -266,7 +345,9 @@ async function processAuthentication( export { promptPassword, + promptNewPassword, processPassword, + processNewPassword, processRecoveryCode, processClientOptions, processClientStatus, diff --git a/src/bin/utils/utils.ts b/src/bin/utils/utils.ts index 2978341ee..fcddf74f3 100644 --- a/src/bin/utils/utils.ts +++ b/src/bin/utils/utils.ts @@ -97,13 +97,16 @@ async function retryAuthentication( try { return await f(meta); } catch (e) { - // If it is any exception other than ErrorClientAuthMissing, throw the exception - // If it is ErrorClientAuthMissing and unattended, throw the exception + // If it is unattended, throw the exception + // Don't enter into a retry loop when unattended // Unattended means that either the `PK_PASSWORD` or `PK_TOKEN` was set + if ('PK_PASSWORD' in process.env || 'PK_TOKEN' in process.env) { + throw e; + } + // If it is exception is not missing or denied, then throw the exception if ( - !(e instanceof clientErrors.ErrorClientAuthMissing) || - 'PK_PASSWORD' in process.env || - 'PK_TOKEN' in process.env + !(e instanceof clientErrors.ErrorClientAuthMissing) && + !(e instanceof clientErrors.ErrorClientAuthDenied) ) { throw e; } @@ -120,6 +123,7 @@ async function retryAuthentication( try { return await f(meta); } catch (e) { + // The auth cannot be missing, so when it is denied do we retry if (!(e instanceof clientErrors.ErrorClientAuthDenied)) { throw e; } diff --git a/src/bin/vaults/CommandClone.ts b/src/bin/vaults/CommandClone.ts index e5867dcf9..a0af7d2ad 100644 --- a/src/bin/vaults/CommandClone.ts +++ b/src/bin/vaults/CommandClone.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -22,7 +20,6 @@ class CommandClone extends CommandPolykey { '../../proto/js/polykey/v1/vaults/vaults_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandClone extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,12 +44,6 @@ class CommandClone extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const nodeMessage = new nodesPB.Node(); const vaultCloneMessage = new vaultsPB.Clone(); @@ -57,22 +51,12 @@ class CommandClone extends CommandPolykey { vaultCloneMessage.setNode(nodeMessage); nodeMessage.setNodeId(nodeId); vaultMessage.setNameOrId(vaultNameOrId); - await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.vaultsClone(vaultCloneMessage, auth), + (auth) => pkClient.grpcClient.vaultsClone(vaultCloneMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Clone Vault: ${vaultMessage.getNameOrId()} from Node: ${nodeMessage.getNodeId()} successful`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandCreate.ts b/src/bin/vaults/CommandCreate.ts index 3cd40cf0f..511d69ed0 100644 --- a/src/bin/vaults/CommandCreate.ts +++ b/src/bin/vaults/CommandCreate.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -21,7 +19,6 @@ class CommandCreate extends CommandPolykey { const vaultsPB = await import( '../../proto/js/polykey/v1/vaults/vaults_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +27,11 @@ class CommandCreate extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,20 +43,12 @@ class CommandCreate extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(vaultName); - const response = await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.vaultsCreate(vaultMessage, auth), + (auth) => pkClient.grpcClient.vaultsCreate(vaultMessage, auth), meta, ); - process.stdout.write( binUtils.outputFormatter({ type: options.format === 'json' ? 'json' : 'list', @@ -64,7 +56,7 @@ class CommandCreate extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandDelete.ts b/src/bin/vaults/CommandDelete.ts index 50134c1fa..e5bd72b32 100644 --- a/src/bin/vaults/CommandDelete.ts +++ b/src/bin/vaults/CommandDelete.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -20,7 +18,6 @@ class CommandDelete extends CommandPolykey { const vaultsPB = await import( '../../proto/js/polykey/v1/vaults/vaults_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -29,8 +26,11 @@ class CommandDelete extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -42,28 +42,14 @@ class CommandDelete extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(vaultName); await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.vaultsDelete(vaultMessage, auth), + (auth) => pkClient.grpcClient.vaultsDelete(vaultMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [`Vault: ${vaultMessage.getNameOrId()} deleted successfully`], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandList.ts b/src/bin/vaults/CommandList.ts index f947f5839..3a5b3f1f9 100644 --- a/src/bin/vaults/CommandList.ts +++ b/src/bin/vaults/CommandList.ts @@ -17,7 +17,6 @@ class CommandList extends CommandPolykey { this.action(async (options) => { const { default: PolykeyClient } = await import('../../PolykeyClient'); const utilsPB = await import('../../proto/js/polykey/v1/utils/utils_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -26,8 +25,11 @@ class CommandList extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -39,17 +41,11 @@ class CommandList extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const emptyMessage = new utilsPB.EmptyMessage(); const data = await binUtils.retryAuthentication( async (meta: Metadata) => { const data: Array = []; - const stream = grpcClient.vaultsList(emptyMessage, meta); + const stream = pkClient.grpcClient.vaultsList(emptyMessage, meta); for await (const vault of stream) { data.push(`${vault.getVaultName()}:\t\t${vault.getVaultId()}`); } @@ -64,7 +60,7 @@ class CommandList extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandLog.ts b/src/bin/vaults/CommandLog.ts index 6d0829f88..12e1f6a3f 100644 --- a/src/bin/vaults/CommandLog.ts +++ b/src/bin/vaults/CommandLog.ts @@ -25,7 +25,6 @@ class CommandLog extends CommandPolykey { const vaultsPB = await import( '../../proto/js/polykey/v1/vaults/vaults_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -34,8 +33,11 @@ class CommandLog extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -47,23 +49,19 @@ class CommandLog extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); vaultMessage.setNameOrId(vault); const vaultsLogMessage = new vaultsPB.Log(); vaultsLogMessage.setVault(vaultMessage); vaultsLogMessage.setLogDepth(options.depth); vaultsLogMessage.setCommitId(options.commitId ?? ''); - const data = await binUtils.retryAuthentication( async (meta: Metadata) => { const data: Array = []; - const stream = grpcClient.vaultsLog(vaultsLogMessage, meta); + const stream = pkClient.grpcClient.vaultsLog( + vaultsLogMessage, + meta, + ); for await (const commit of stream) { const timeStamp = commit.getTimeStamp(); const date = new Date(timeStamp); @@ -83,7 +81,7 @@ class CommandLog extends CommandPolykey { }), ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandPull.ts b/src/bin/vaults/CommandPull.ts index 6c195817e..dc549deca 100644 --- a/src/bin/vaults/CommandPull.ts +++ b/src/bin/vaults/CommandPull.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -22,7 +20,6 @@ class CommandPull extends CommandPolykey { '../../proto/js/polykey/v1/vaults/vaults_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandPull extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,12 +44,6 @@ class CommandPull extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const nodeMessage = new nodesPB.Node(); const vaultPullMessage = new vaultsPB.Pull(); @@ -57,22 +51,12 @@ class CommandPull extends CommandPolykey { vaultPullMessage.setNode(nodeMessage); nodeMessage.setNodeId(nodeId); vaultMessage.setNameOrId(vaultName); - await binUtils.retryAuthentication( - (auth?: Metadata) => grpcClient.vaultsPull(vaultPullMessage, auth), + (auth) => pkClient.grpcClient.vaultsPull(vaultPullMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Pull Vault: ${vaultMessage.getNameOrId()} from Node: ${nodeMessage.getNodeId()} successful`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandRename.ts b/src/bin/vaults/CommandRename.ts index 97ed9fcdc..9df0f2d75 100644 --- a/src/bin/vaults/CommandRename.ts +++ b/src/bin/vaults/CommandRename.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -21,7 +19,6 @@ class CommandRename extends CommandPolykey { const vaultsPB = await import( '../../proto/js/polykey/v1/vaults/vaults_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +27,11 @@ class CommandRename extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,34 +43,17 @@ class CommandRename extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const vaultRenameMessage = new vaultsPB.Rename(); vaultRenameMessage.setVault(vaultMessage); vaultMessage.setNameOrId(vaultName); vaultRenameMessage.setNewName(newVaultName); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsRename(vaultRenameMessage, auth), + (auth) => pkClient.grpcClient.vaultsRename(vaultRenameMessage, auth), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Renamed vault: ${vaultMessage.getNameOrId()} to ${vaultRenameMessage.getNewName()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandShare.ts b/src/bin/vaults/CommandShare.ts index 0c88b11b7..12a53a202 100644 --- a/src/bin/vaults/CommandShare.ts +++ b/src/bin/vaults/CommandShare.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -22,7 +20,6 @@ class CommandShare extends CommandPolykey { '../../proto/js/polykey/v1/vaults/vaults_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandShare extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,12 +44,6 @@ class CommandShare extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const nodeMessage = new nodesPB.Node(); const setVaultPermsMessage = new vaultsPB.PermSet(); @@ -57,27 +51,16 @@ class CommandShare extends CommandPolykey { setVaultPermsMessage.setNode(nodeMessage); vaultMessage.setNameOrId(vaultName); nodeMessage.setNodeId(nodeId); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsPermissionsSet(setVaultPermsMessage, auth), + (auth) => + pkClient.grpcClient.vaultsPermissionsSet( + setVaultPermsMessage, + auth, + ), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Shared Vault: ${setVaultPermsMessage - .getVault() - ?.getNameOrId()} to: ${setVaultPermsMessage - .getNode() - ?.getNodeId()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandUnshare.ts b/src/bin/vaults/CommandUnshare.ts index 671fc094a..8a4cabbd4 100644 --- a/src/bin/vaults/CommandUnshare.ts +++ b/src/bin/vaults/CommandUnshare.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -22,7 +20,6 @@ class CommandUnshare extends CommandPolykey { '../../proto/js/polykey/v1/vaults/vaults_pb' ); const nodesPB = await import('../../proto/js/polykey/v1/nodes/nodes_pb'); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -31,8 +28,11 @@ class CommandUnshare extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -44,12 +44,6 @@ class CommandUnshare extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const unsetVaultPermsMessage = new vaultsPB.PermUnset(); const vaultMessage = new vaultsPB.Vault(); const nodeMessage = new nodesPB.Node(); @@ -57,27 +51,16 @@ class CommandUnshare extends CommandPolykey { unsetVaultPermsMessage.setNode(nodeMessage); vaultMessage.setNameOrId(vaultName); nodeMessage.setNodeId(nodeId); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsPermissionsUnset(unsetVaultPermsMessage, auth), + (auth) => + pkClient.grpcClient.vaultsPermissionsUnset( + unsetVaultPermsMessage, + auth, + ), meta, ); - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: [ - `Unshared Vault: ${unsetVaultPermsMessage - .getVault() - ?.getNameOrId()} to: ${unsetVaultPermsMessage - .getNode() - ?.getNodeId()}`, - ], - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/bin/vaults/CommandVersion.ts b/src/bin/vaults/CommandVersion.ts index 051acecfd..e2262d4fa 100644 --- a/src/bin/vaults/CommandVersion.ts +++ b/src/bin/vaults/CommandVersion.ts @@ -1,5 +1,3 @@ -import type { Metadata } from '@grpc/grpc-js'; - import type PolykeyClient from '../../PolykeyClient'; import CommandPolykey from '../CommandPolykey'; import * as binUtils from '../utils'; @@ -21,7 +19,6 @@ class CommandVersion extends CommandPolykey { const vaultsPB = await import( '../../proto/js/polykey/v1/vaults/vaults_pb' ); - const clientOptions = await binProcessors.processClientOptions( options.nodePath, options.nodeId, @@ -30,8 +27,11 @@ class CommandVersion extends CommandPolykey { this.fs, this.logger.getChild(binProcessors.processClientOptions.name), ); - - let pkClient: PolykeyClient | undefined; + const meta = await binProcessors.processAuthentication( + options.passwordFile, + this.fs, + ); + let pkClient: PolykeyClient; this.exitHandlers.handlers.push(async () => { if (pkClient != null) await pkClient.stop(); }); @@ -43,30 +43,16 @@ class CommandVersion extends CommandPolykey { port: clientOptions.clientPort, logger: this.logger.getChild(PolykeyClient.name), }); - - const meta = await binProcessors.processAuthentication( - options.passwordFile, - this.fs, - ); - const grpcClient = pkClient.grpcClient; const vaultMessage = new vaultsPB.Vault(); const vaultsVersionMessage = new vaultsPB.Version(); vaultMessage.setNameOrId(vault); vaultsVersionMessage.setVault(vaultMessage); vaultsVersionMessage.setVersionId(versionId); - await binUtils.retryAuthentication( - (auth?: Metadata) => - grpcClient.vaultsVersion(vaultsVersionMessage, auth), + (auth) => + pkClient.grpcClient.vaultsVersion(vaultsVersionMessage, auth), meta, ); - - let successMessage = [`Vault ${vault} is now at version ${versionId}.`]; - - if (versionId.toLowerCase() === 'last') { - successMessage = [`Vault ${vault} is now at the latest version.`]; - } - /** * Previous status message: * --- @@ -74,15 +60,8 @@ class CommandVersion extends CommandPolykey { * will discard all changes applied to the vault in later versions. You will * not be able to return to these later versions if changes are made. */ - - process.stdout.write( - binUtils.outputFormatter({ - type: options.format === 'json' ? 'json' : 'list', - data: successMessage, - }), - ); } finally { - if (pkClient != null) await pkClient.stop(); + if (pkClient! != null) await pkClient.stop(); } }); } diff --git a/src/client/GRPCClientClient.ts b/src/client/GRPCClientClient.ts index 9beec1423..0eb4e5659 100644 --- a/src/client/GRPCClientClient.ts +++ b/src/client/GRPCClientClient.ts @@ -8,7 +8,6 @@ import type * as agentPB from '../proto/js/polykey/v1/agent/agent_pb'; import type * as vaultsPB from '../proto/js/polykey/v1/vaults/vaults_pb'; import type * as nodesPB from '../proto/js/polykey/v1/nodes/nodes_pb'; import type * as notificationsPB from '../proto/js/polykey/v1/notifications/notifications_pb'; -import type * as sessionsPB from '../proto/js/polykey/v1/sessions/sessions_pb'; import type * as gestaltsPB from '../proto/js/polykey/v1/gestalts/gestalts_pb'; import type * as identitiesPB from '../proto/js/polykey/v1/identities/identities_pb'; import type * as keysPB from '../proto/js/polykey/v1/keys/keys_pb'; @@ -54,17 +53,18 @@ class GRPCClientClient extends GRPCClient { if (session != null) { interceptors.push(clientUtils.sessionInterceptor(session)); } - const { client, serverCertChain } = await super.createClient({ - clientConstructor: ClientServiceClient, - nodeId, - host, - port, - tlsConfig, - proxyConfig, - timeout, - interceptors, - logger, - }); + const { client, serverCertChain, flowCountInterceptor } = + await super.createClient({ + clientConstructor: ClientServiceClient, + nodeId, + host, + port, + tlsConfig, + proxyConfig, + timeout, + interceptors, + logger, + }); const grpcClientClient = new GRPCClientClient({ client, nodeId, @@ -73,6 +73,7 @@ class GRPCClientClient extends GRPCClient { tlsConfig, proxyConfig, serverCertChain, + flowCountInterceptor, logger, }); logger.info(`Created ${this.name}`); @@ -103,23 +104,15 @@ class GRPCClientClient extends GRPCClient { @ready(new clientErrors.ErrorClientClientDestroyed()) public sessionsUnlock(...args) { - return grpcUtils.promisifyUnaryCall( + return grpcUtils.promisifyUnaryCall( this.client, this.client.sessionsUnlock, )(...args); } - @ready(new clientErrors.ErrorClientClientDestroyed()) - public sessionsRefresh(...args) { - return grpcUtils.promisifyUnaryCall( - this.client, - this.client.sessionsRefresh, - )(...args); - } - @ready(new clientErrors.ErrorClientClientDestroyed()) public sessionsLockAll(...args) { - return grpcUtils.promisifyUnaryCall( + return grpcUtils.promisifyUnaryCall( this.client, this.client.sessionsLockAll, )(...args); diff --git a/src/client/clientService.ts b/src/client/clientService.ts index 5b4a7ef6d..ec3946311 100644 --- a/src/client/clientService.ts +++ b/src/client/clientService.ts @@ -77,7 +77,6 @@ function createClientService({ ...createSessionsRPC({ authenticate, sessionManager, - keyManager, }), ...createVaultRPC({ vaultManager, @@ -121,6 +120,7 @@ function createClientService({ const write = promisify(call.write).bind(call); await write(nodeMessage); call.end(); + return; }, agentStop: async ( call: grpc.ServerUnaryCall, @@ -128,7 +128,8 @@ function createClientService({ ): Promise => { const response = new utilsPB.EmptyMessage(); if (!polykeyAgent.running) { - return callback(null, response); + callback(null, response); + return; } try { const metadata = await authenticate(call.metadata); @@ -137,6 +138,7 @@ function createClientService({ callback(null, response); } catch (err) { callback(grpcUtils.fromError(err), null); + return; } // Stop is called after GRPC resources are cleared await polykeyAgent.stop(); diff --git a/src/client/rpcGestalts.ts b/src/client/rpcGestalts.ts index ef0731f72..afbe69ac6 100644 --- a/src/client/rpcGestalts.ts +++ b/src/client/rpcGestalts.ts @@ -42,10 +42,12 @@ const createGestaltsRPC = ({ if (gestalt != null) { response.setGestaltGraph(JSON.stringify(gestalt)); } + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, gestaltsGestaltGetByIdentity: async ( call: grpc.ServerUnaryCall, @@ -63,10 +65,12 @@ const createGestaltsRPC = ({ if (gestalt != null) { response.setGestaltGraph(JSON.stringify(gestalt)); } + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, gestaltsGestaltList: async ( call: grpc.ServerWritableStream, @@ -84,8 +88,10 @@ const createGestaltsRPC = ({ await genWritable.next(gestaltMessage); } await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, gestaltsDiscoveryByNode: async ( @@ -93,7 +99,7 @@ const createGestaltsRPC = ({ callback: grpc.sendUnaryData, ): Promise => { const info = call.request; - const emptyMessage = new utilsPB.EmptyMessage(); + const response = new utilsPB.EmptyMessage(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); @@ -104,17 +110,19 @@ const createGestaltsRPC = ({ for await (const _ of gen) { // Empty } + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, emptyMessage); }, gestaltsDiscoveryByIdentity: async ( call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { const info = call.request; - const emptyMessage = new utilsPB.EmptyMessage(); + const response = new utilsPB.EmptyMessage(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); @@ -126,10 +134,12 @@ const createGestaltsRPC = ({ for await (const _ of gen) { // Empty } + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, emptyMessage); }, gestaltsActionsGetByNode: async ( call: grpc.ServerUnaryCall, @@ -152,10 +162,12 @@ const createGestaltsRPC = ({ const actions = Object.keys(result); response.setActionList(actions); } + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, gestaltsActionsGetByIdentity: async ( call: grpc.ServerUnaryCall, @@ -181,10 +193,12 @@ const createGestaltsRPC = ({ const actions = Object.keys(result); response.setActionList(actions); } + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, gestaltsActionsSetByNode: async ( call: grpc.ServerUnaryCall, @@ -212,10 +226,12 @@ const createGestaltsRPC = ({ const action = makeGestaltAction(info.getAction()); const nodeId = makeNodeId(info.getNode()?.getNodeId()); await gestaltGraph.setGestaltActionByNode(nodeId, action); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, gestaltsActionsSetByIdentity: async ( call: grpc.ServerUnaryCall, @@ -248,10 +264,12 @@ const createGestaltsRPC = ({ identityId, action, ); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, gestaltsActionsUnsetByNode: async ( call: grpc.ServerUnaryCall, @@ -279,10 +297,12 @@ const createGestaltsRPC = ({ const action = makeGestaltAction(info.getAction()); const nodeId = makeNodeId(info.getNode()?.getNodeId()); await gestaltGraph.unsetGestaltActionByNode(nodeId, action); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, gestaltsActionsUnsetByIdentity: async ( call: grpc.ServerUnaryCall, @@ -315,10 +335,12 @@ const createGestaltsRPC = ({ identityId, action, ); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, }; }; diff --git a/src/client/rpcIdentities.ts b/src/client/rpcIdentities.ts index 5ac508d58..2810208df 100644 --- a/src/client/rpcIdentities.ts +++ b/src/client/rpcIdentities.ts @@ -62,8 +62,10 @@ const createIdentitiesRPC = ({ response.setMessage(userName); await genWritable.next(response); await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, identitiesTokenPut: async ( @@ -84,10 +86,12 @@ const createIdentitiesRPC = ({ provider?.getMessage() as IdentityId, { accessToken: call.request.getToken() } as TokenData, ); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, identitiesTokenGet: async ( call: grpc.ServerUnaryCall, @@ -103,10 +107,12 @@ const createIdentitiesRPC = ({ call.request.getMessage() as IdentityId, ); response.setToken(JSON.stringify(tokens)); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, identitiesTokenDelete: async ( call: grpc.ServerUnaryCall, @@ -121,10 +127,12 @@ const createIdentitiesRPC = ({ call.request.getProviderId() as ProviderId, call.request.getMessage() as IdentityId, ); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, identitiesProvidersList: async ( call: grpc.ServerUnaryCall, @@ -137,10 +145,12 @@ const createIdentitiesRPC = ({ const providers = identitiesManager.getProviders(); response.setProviderId(JSON.stringify(Object.keys(providers))); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, identitiesInfoGetConnected: async ( call: grpc.ServerWritableStream< @@ -182,8 +192,10 @@ const createIdentitiesRPC = ({ await genWritable.next(identityInfoMessage); } await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, /** @@ -193,22 +205,24 @@ const createIdentitiesRPC = ({ call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { + const response = new identitiesPB.Provider(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); // Get's an identity out of all identities. - const providerMessage = new identitiesPB.Provider(); const providerId = call.request.getProviderId() as ProviderId; const provider = identitiesManager.getProvider(providerId); if (provider == null) throw Error(`Invalid provider: ${providerId}`); const identities = await provider.getAuthIdentityIds(); if (identities.length !== 0) { - providerMessage.setProviderId(providerId); - providerMessage.setMessage(identities[0]); + response.setProviderId(providerId); + response.setMessage(identities[0]); } else throw Error(`No identities found for provider: ${providerId}`); - callback(null, providerMessage); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, /** @@ -220,6 +234,7 @@ const createIdentitiesRPC = ({ ): Promise => { // To augment a keynode we need a provider, generate an oauthkey and then const info = call.request; + const response = new utilsPB.EmptyMessage(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); @@ -239,11 +254,12 @@ const createIdentitiesRPC = ({ await gestaltGraph.linkNodeAndIdentity(nodeInfo, identityInfo); // Need to call this // it takes NodeInfo and IdentityInfo. // Getting and creating NodeInfo is blocked by + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - const emptyMessage = new utilsPB.EmptyMessage(); - callback(null, emptyMessage); }, }; }; diff --git a/src/client/rpcKeys.ts b/src/client/rpcKeys.ts index a52ca16b9..3363dd326 100644 --- a/src/client/rpcKeys.ts +++ b/src/client/rpcKeys.ts @@ -39,10 +39,12 @@ const createKeysRPC = ({ const keyPair = keyManager.getRootKeyPairPem(); response.setPublic(keyPair.publicKey); response.setPrivate(keyPair.privateKey); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysKeyPairReset: async ( call: grpc.ServerUnaryCall, @@ -67,10 +69,12 @@ const createKeysRPC = ({ // Finally, refresh the node buckets await nodeManager.refreshBuckets(); }); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysKeyPairRenew: async ( call: grpc.ServerUnaryCall, @@ -94,10 +98,12 @@ const createKeysRPC = ({ // Finally, refresh the node buckets await nodeManager.refreshBuckets(); }); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysEncrypt: async ( call: grpc.ServerUnaryCall, @@ -112,10 +118,12 @@ const createKeysRPC = ({ Buffer.from(call.request.getData(), 'binary'), ); response.setData(data.toString('binary')); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysDecrypt: async ( call: grpc.ServerUnaryCall, @@ -130,10 +138,12 @@ const createKeysRPC = ({ Buffer.from(call.request.getData(), 'binary'), ); response.setData(data.toString('binary')); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysSign: async ( call: grpc.ServerUnaryCall, @@ -148,10 +158,12 @@ const createKeysRPC = ({ Buffer.from(call.request.getData(), 'binary'), ); response.setSignature(signature.toString('binary')); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysVerify: async ( call: grpc.ServerUnaryCall, @@ -167,10 +179,12 @@ const createKeysRPC = ({ Buffer.from(call.request.getSignature(), 'binary'), ); response.setSuccess(status); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysPasswordChange: async ( call: grpc.ServerUnaryCall, @@ -182,10 +196,12 @@ const createKeysRPC = ({ call.sendMetadata(metadata); await keyManager.changePassword(call.request.getPassword()); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysCertsGet: async ( call: grpc.ServerUnaryCall, @@ -198,10 +214,12 @@ const createKeysRPC = ({ const cert = keyManager.getRootCertPem(); response.setCert(cert); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, keysCertsChainGet: async ( call: grpc.ServerWritableStream, @@ -219,8 +237,10 @@ const createKeysRPC = ({ await genWritable.next(certMessage); } await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, }; diff --git a/src/client/rpcNodes.ts b/src/client/rpcNodes.ts index 2a0c9ed17..6579a59d1 100644 --- a/src/client/rpcNodes.ts +++ b/src/client/rpcNodes.ts @@ -50,10 +50,12 @@ const createNodesRPC = ({ ip: call.request.getAddress()!.getHost(), port: call.request.getAddress()!.getPort(), } as NodeAddress); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, /** * Checks if a remote node is online. @@ -71,10 +73,12 @@ const createNodesRPC = ({ makeNodeId(call.request.getNodeId()), ); response.setSuccess(status); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, /** * Checks whether there is an existing Gestalt Invitation from the other node. @@ -108,10 +112,12 @@ const createNodesRPC = ({ await nodeManager.claimNode(remoteNodeId); response.setSuccess(true); } + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, /** * Attempts to get the node address of a provided node ID (by contacting @@ -134,10 +140,12 @@ const createNodesRPC = ({ .setAddress( new nodesPB.Address().setHost(address.ip).setPort(address.port), ); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, }; }; diff --git a/src/client/rpcNotifications.ts b/src/client/rpcNotifications.ts index 0376b6077..62507d444 100644 --- a/src/client/rpcNotifications.ts +++ b/src/client/rpcNotifications.ts @@ -20,6 +20,7 @@ const createNotificationsRPC = ({ call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { + const response = new utilsPB.EmptyMessage(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); @@ -32,11 +33,12 @@ const createNotificationsRPC = ({ const validatedData = notificationsUtils.validateGeneralNotification(data); await notificationsManager.sendNotification(receivingId, validatedData); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - const emptyMessage = new utilsPB.EmptyMessage(); - callback(null, emptyMessage); }, notificationsRead: async ( call: grpc.ServerUnaryCall, @@ -91,25 +93,29 @@ const createNotificationsRPC = ({ notifMessages.push(notificationsMessage); } response.setNotificationList(notifMessages); + callback(null, response); + return; } catch (err) { - callback(grpcUtils.fromError(err), response); + callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, notificationsClear: async ( call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { + const response = new utilsPB.EmptyMessage(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); await notificationsManager.clearNotifications(); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - const emptyMessage = new utilsPB.EmptyMessage(); - callback(null, emptyMessage); }, }; }; diff --git a/src/client/rpcSessions.ts b/src/client/rpcSessions.ts index 5f541b540..e535c5f67 100644 --- a/src/client/rpcSessions.ts +++ b/src/client/rpcSessions.ts @@ -1,67 +1,47 @@ import type { SessionManager } from '../sessions'; -import type { KeyManager } from '../keys'; - import type * as grpc from '@grpc/grpc-js'; import type * as utils from './utils'; -import * as clientUtils from '../client/utils'; import * as grpcUtils from '../grpc/utils'; import * as utilsPB from '../proto/js/polykey/v1/utils/utils_pb'; -import * as sessionsPB from '../proto/js/polykey/v1/sessions/sessions_pb'; const createSessionsRPC = ({ authenticate, sessionManager, - keyManager, }: { authenticate: utils.Authenticate; sessionManager: SessionManager; - keyManager: KeyManager; }) => { return { sessionsUnlock: async ( - call: grpc.ServerUnaryCall, - callback: grpc.sendUnaryData, - ): Promise => { - const response = new sessionsPB.Token(); - try { - const password = call.request.getPassword(); - await keyManager.checkPassword(password); - const token = await sessionManager.createToken(); - response.setToken(token); - call.sendMetadata(clientUtils.encodeAuthFromSession(token)); - } catch (err) { - callback(grpcUtils.fromError(err), null); - } - callback(null, response); - }, - sessionsRefresh: async ( - call: grpc.ServerUnaryCall, - callback: grpc.sendUnaryData, + call: grpc.ServerUnaryCall, + callback: grpc.sendUnaryData, ): Promise => { - const response = new sessionsPB.Token(); + const response = new utilsPB.EmptyMessage(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); - response.setToken(await sessionManager.createToken()); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, sessionsLockAll: async ( - call: grpc.ServerUnaryCall, - callback: grpc.sendUnaryData, + call: grpc.ServerUnaryCall, + callback: grpc.sendUnaryData, ): Promise => { - const response = new utilsPB.StatusMessage(); + const response = new utilsPB.EmptyMessage(); try { const metadata = await authenticate(call.metadata); call.sendMetadata(metadata); await sessionManager.resetKey(); - response.setSuccess(true); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, }; }; diff --git a/src/client/rpcStatus.ts b/src/client/rpcStatus.ts index 1d939ead1..d0d1e5480 100644 --- a/src/client/rpcStatus.ts +++ b/src/client/rpcStatus.ts @@ -48,8 +48,10 @@ const createStatusRPC = ({ response.setRootCertPem(keyManager.getRootCertPem()); response.setRootCertChainPem(await keyManager.getRootCertChainPem()); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, }; diff --git a/src/client/rpcVaults.ts b/src/client/rpcVaults.ts index 15158edef..16be5875b 100644 --- a/src/client/rpcVaults.ts +++ b/src/client/rpcVaults.ts @@ -51,8 +51,10 @@ const createVaultRPC = ({ await genWritable.next(((_) => vaultListMessage)()); } await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, vaultsCreate: async ( @@ -69,10 +71,12 @@ const createVaultRPC = ({ call.request.getNameOrId() as VaultName, ); response.setNameOrId(vaultsUtils.makeVaultIdPretty(vault.vaultId)); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } - callback(null, response); }, vaultsRename: async ( call: grpc.ServerUnaryCall, @@ -96,8 +100,10 @@ const createVaultRPC = ({ await vaultManager.renameVault(vaultId, newName); response.setNameOrId(vaultsUtils.makeVaultIdPretty(vaultId)); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsDelete: async ( @@ -117,8 +123,10 @@ const createVaultRPC = ({ await vaultManager.destroyVault(vaultId); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsClone: async ( @@ -150,8 +158,10 @@ const createVaultRPC = ({ // await vaultManager.cloneVault(vaultId, id); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsPull: async ( @@ -181,8 +191,10 @@ const createVaultRPC = ({ // Await vaultManager.pullVault(vaultId, id); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsScan: async ( @@ -203,8 +215,10 @@ const createVaultRPC = ({ await genWritable.next(vaultListMessage); }); await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, vaultsSecretsList: async ( @@ -230,8 +244,10 @@ const createVaultRPC = ({ await genWritable.next(secretMessage); } await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, vaultsSecretsMkdir: async ( @@ -259,8 +275,10 @@ const createVaultRPC = ({ }); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsSecretsStat: async ( @@ -280,8 +298,10 @@ const createVaultRPC = ({ // Const stats = await vaultManager.vaultStats(id); // response.setStats(JSON.stringify(stats));); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsSecretsDelete: async ( @@ -307,8 +327,10 @@ const createVaultRPC = ({ await vaultOps.deleteSecret(vault, secretName); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsSecretsEdit: async ( @@ -340,8 +362,10 @@ const createVaultRPC = ({ await vaultOps.updateSecret(vault, secretName, secretContent); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsSecretsGet: async ( @@ -368,8 +392,10 @@ const createVaultRPC = ({ response.setSecretContent(secretContent); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsSecretsRename: async ( @@ -401,8 +427,10 @@ const createVaultRPC = ({ await vaultOps.renameSecret(vault, oldSecret, newSecret); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsSecretsNew: async ( @@ -429,8 +457,10 @@ const createVaultRPC = ({ await vaultOps.addSecret(vault, secret, content); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsSecretsNewDir: async ( @@ -456,8 +486,10 @@ const createVaultRPC = ({ await vaultOps.addSecretDirectory(vault, secretsPath, fs); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsPermissionsSet: async ( @@ -485,8 +517,10 @@ const createVaultRPC = ({ const response = new utilsPB.StatusMessage(); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsPermissionsUnset: async ( @@ -514,8 +548,10 @@ const createVaultRPC = ({ const response = new utilsPB.StatusMessage(); response.setSuccess(true); callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsPermissions: async ( @@ -556,14 +592,17 @@ const createVaultRPC = ({ // await genWritable.next(permissionMessage); // } await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, vaultsVersion: async ( call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData, ): Promise => { + const response = new vaultsPB.VersionResult(); try { // Checking session token const metadata = await authenticate(call.metadata); @@ -594,13 +633,14 @@ const createVaultRPC = ({ const isLatestVersion = latestOid === currentVersionId; // Creating message - const vaultsVersionResultMessage = new vaultsPB.VersionResult(); - vaultsVersionResultMessage.setIsLatestVersion(isLatestVersion); + response.setIsLatestVersion(isLatestVersion); // Sending message - callback(null, vaultsVersionResultMessage); + callback(null, response); + return; } catch (err) { callback(grpcUtils.fromError(err), null); + return; } }, vaultsLog: async ( @@ -638,8 +678,10 @@ const createVaultRPC = ({ await genWritable.next(vaultsLogEntryMessage); } await genWritable.next(null); + return; } catch (err) { await genWritable.throw(err); + return; } }, }; diff --git a/src/client/utils/index.ts b/src/client/utils/index.ts new file mode 100644 index 000000000..04bca77e0 --- /dev/null +++ b/src/client/utils/index.ts @@ -0,0 +1 @@ +export * from './utils'; diff --git a/src/client/utils.ts b/src/client/utils/utils.ts similarity index 94% rename from src/client/utils.ts rename to src/client/utils/utils.ts index 1ed23ea1b..581d511e0 100644 --- a/src/client/utils.ts +++ b/src/client/utils/utils.ts @@ -3,13 +3,12 @@ import type { Interceptor, InterceptorOptions, } from '@grpc/grpc-js/build/src/client-interceptors'; -import type { KeyManager } from '../keys'; -import type { Session, SessionManager } from '../sessions'; -import type { SessionToken } from '../sessions/types'; - +import type { KeyManager } from '../../keys'; +import type { Session, SessionManager } from '../../sessions'; +import type { SessionToken } from '../../sessions/types'; import * as grpc from '@grpc/grpc-js'; import * as base64 from 'multiformats/bases/base64'; -import * as clientErrors from './errors'; +import * as clientErrors from '../errors'; /** * Session interceptor middleware for authenticatio @@ -76,7 +75,7 @@ function authenticator( const encoded = auth.substring(6); const decoded = base64.base64pad.baseDecode(encoded); const decodedString = String.fromCharCode(...decoded); - const match = decodedString.match(/:(.+)/); + const match = decodedString.match(/:(.*)/); if (match == null) { throw new clientErrors.ErrorClientAuthFormat(); } diff --git a/src/grpc/GRPCClient.ts b/src/grpc/GRPCClient.ts index 98097bf11..1c2e02bd4 100644 --- a/src/grpc/GRPCClient.ts +++ b/src/grpc/GRPCClient.ts @@ -16,7 +16,7 @@ import * as grpcUtils from './utils'; import * as grpcErrors from './errors'; import { utils as keysUtils } from '../keys'; import { utils as networkUtils, errors as networkErrors } from '../network'; -import { promisify } from '../utils'; +import { promisify, promise, timerStart, timerStop } from '../utils'; abstract class GRPCClient { /** @@ -55,6 +55,7 @@ abstract class GRPCClient { logger?: Logger; }): Promise<{ client: T; + flowCountInterceptor: grpcUtils.FlowCountInterceptor; serverCertChain?: Array; }> { const address = networkUtils.buildAddress(host, port); @@ -80,9 +81,10 @@ abstract class GRPCClient { // Prevents complaints with having an ip address as the server name 'grpc.ssl_target_name_override': nodeId, }; + const flowCountInterceptor = new grpcUtils.FlowCountInterceptor(); const clientOptions: ClientOptions = { // Interceptor middleware on every call - interceptors, + interceptors: [flowCountInterceptor.interceptor, ...interceptors], }; let client: T; if (proxyConfig == null) { @@ -147,7 +149,7 @@ abstract class GRPCClient { } } logger.info(`Created ${this.name} connecting to ${address}`); - return { client, serverCertChain }; + return { client, serverCertChain, flowCountInterceptor }; } public readonly nodeId: NodeId; @@ -159,6 +161,7 @@ abstract class GRPCClient { protected logger: Logger; protected client: T; protected serverCertChain?: Array; + protected flowCountInterceptor?: grpcUtils.FlowCountInterceptor; protected _secured: boolean = false; constructor({ @@ -169,6 +172,7 @@ abstract class GRPCClient { tlsConfig, proxyConfig, serverCertChain, + flowCountInterceptor, logger, }: { client: T; @@ -178,6 +182,7 @@ abstract class GRPCClient { tlsConfig?: Partial; proxyConfig?: ProxyConfig; serverCertChain?: Array; + flowCountInterceptor?: grpcUtils.FlowCountInterceptor; logger: Logger; }) { this.logger = logger; @@ -188,6 +193,7 @@ abstract class GRPCClient { this.tlsConfig = tlsConfig; this.proxyConfig = proxyConfig; this.serverCertChain = serverCertChain; + this.flowCountInterceptor = flowCountInterceptor; if (tlsConfig != null) { this._secured = true; } @@ -197,7 +203,11 @@ abstract class GRPCClient { return this._secured; } - public async destroy(): Promise { + public async destroy({ + timeout, + }: { + timeout?: number; + } = {}): Promise { const address = `${this.host}:${this.port}`; this.logger.info( `Destroying ${this.constructor.name} connected to ${address}`, @@ -205,6 +215,32 @@ abstract class GRPCClient { // This currently doesn't stop all inflight requests // https://github.com/grpc/grpc-node/issues/1340 this.client.close(); + // Block until all flow count is empty + // This ensures asynchronous interceptors are completed + // Before this function returns + if ( + this.flowCountInterceptor != null && + this.flowCountInterceptor.flowCount !== 0 + ) { + const { p: flowEmptyP, resolveP: resolveFlowEmptyP } = promise(); + this.flowCountInterceptor.once('empty', () => { + resolveFlowEmptyP(); + }); + const timer = timeout != null ? timerStart(timeout) : undefined; + try { + await Promise.race([ + flowEmptyP, + ...(timer != null ? [timer.timerP] : []), + ]); + } finally { + if (timer != null) timerStop(timer); + } + if (timer?.timedOut) { + this.logger.info( + `Timed out stopping ${this.constructor.name}, forcing destroy`, + ); + } + } this.logger.info( `Destroyed ${this.constructor.name} connected to ${address}`, ); diff --git a/src/grpc/utils/FlowCountInterceptor.ts b/src/grpc/utils/FlowCountInterceptor.ts new file mode 100644 index 000000000..b4aefb57e --- /dev/null +++ b/src/grpc/utils/FlowCountInterceptor.ts @@ -0,0 +1,105 @@ +import type { + NextCall, + Interceptor, + InterceptorOptions, +} from '@grpc/grpc-js/build/src/client-interceptors'; +import EventEmitter from 'events'; +import Counter from 'resource-counter'; +import * as grpc from '@grpc/grpc-js'; + +/** + * Client-side flow count interceptor + * A flow count is a count of the number flows + * A flow is the entire asynchronous GRPC call including asynchronous interceptor operations + * Except for onReceiveMessage, any asynchronous operations in the inteceptors counts towards an active flow + * Must be used as the FIRST interceptor in the interceptor list + * This is only necessary while GRPC doesn't support awaiting asynchronous interceptors + */ +class FlowCountInterceptor extends EventEmitter { + /** + * This is the actual interceptor needed by GRPC + * It is an arrow function property so that `this` is bound + */ + public readonly interceptor: Interceptor = ( + options: InterceptorOptions, + nextCall: NextCall, + ) => { + const flowId = this.createFlow(); + const requester = { + start: (metadata, _, next) => { + next(metadata, { + onReceiveMetadata: (metadata, next) => { + // On leading metadata, subtract the flow count + // Leading metadata is always received first before messages + // Or steam data chunks + // And before the trailing status + this.subtractFlow(flowId); + next(metadata); + }, + onReceiveStatus: (status, next) => { + // Trailing status occurs at the end of responses and streams + if (status.code !== grpc.status.OK) { + // On trailing status, the leading metadata may or may not have executed + // For example exceeding the deadline results in a local + // deadline status which can occur before leading metadata is sent + // If the flow count is 1, then leading metadata has been received + // If the flow count is 2, then the leading metadata has not been received + const flowCount = this.flows.get(flowId); + if (flowCount === 1) { + this.subtractFlow(flowId); + } else if (flowCount === 2) { + this.destroyFlow(flowId); + } + } else { + // Under normal conditions, we woulde expect the leading metadata to have been sent + this.subtractFlow(flowId); + } + next(status); + return; + }, + }); + }, + cancel: (next) => { + // If the client cancels, destroy the flow + this.destroyFlow(flowId); + next(); + return; + }, + }; + return new grpc.InterceptingCall(nextCall(options), requester); + }; + protected flows: Map = new Map(); + protected counter: Counter = new Counter(); + + get flowCount(): number { + return this.flows.size; + } + + protected createFlow(): number { + const flowId = this.counter.allocate(); + // Only 2 asynchronous inbound interceptors have to be tracked + // leading metadata and trailing status interceptors + const flowCount = 2; + this.flows.set(flowId, flowCount); + return flowId; + } + + protected subtractFlow(flowId: number): void { + let count = this.flows.get(flowId)!; + if (--count > 0) { + this.flows.set(flowId, count); + } else { + this.destroyFlow(flowId); + } + } + + protected destroyFlow(flowId: number): void { + this.flows.delete(flowId); + this.counter.deallocate(flowId); + if (this.flows.size === 0) { + this.emit('empty'); + } + } +} + +export default FlowCountInterceptor; diff --git a/src/grpc/utils/index.ts b/src/grpc/utils/index.ts new file mode 100644 index 000000000..73125dbb8 --- /dev/null +++ b/src/grpc/utils/index.ts @@ -0,0 +1,2 @@ +export { default as FlowCountInterceptor } from './FlowCountInterceptor'; +export * from './utils'; diff --git a/src/grpc/utils.ts b/src/grpc/utils/utils.ts similarity index 98% rename from src/grpc/utils.ts rename to src/grpc/utils/utils.ts index f14aeddb3..1dbb4f6bf 100644 --- a/src/grpc/utils.ts +++ b/src/grpc/utils/utils.ts @@ -25,14 +25,14 @@ import type { AsyncGeneratorWritableStreamClient, AsyncGeneratorDuplexStream, AsyncGeneratorDuplexStreamClient, -} from './types'; -import type { CertificatePemChain, PrivateKeyPem } from '../keys/types'; +} from '../types'; +import type { CertificatePemChain, PrivateKeyPem } from '../../keys/types'; import { Buffer } from 'buffer'; import * as grpc from '@grpc/grpc-js'; -import * as grpcErrors from './errors'; -import * as errors from '../errors'; -import { promisify, promise, never } from '../utils'; +import * as grpcErrors from '../errors'; +import * as errors from '../../errors'; +import { promisify, promise, never } from '../../utils'; /** * GRPC insecure credentials for the client diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts index 3e5a38052..152afa5b2 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.d.ts @@ -22,7 +22,6 @@ interface IClientServiceService extends grpc.ServiceDefinition; responseDeserialize: grpc.deserialize; } -interface IClientServiceService_ISessionsUnlock extends grpc.MethodDefinition { +interface IClientServiceService_ISessionsUnlock extends grpc.MethodDefinition { path: "/polykey.v1.ClientService/SessionsUnlock"; requestStream: false; responseStream: false; - requestSerialize: grpc.serialize; - requestDeserialize: grpc.deserialize; - responseSerialize: grpc.serialize; - responseDeserialize: grpc.deserialize; -} -interface IClientServiceService_ISessionsRefresh extends grpc.MethodDefinition { - path: "/polykey.v1.ClientService/SessionsRefresh"; - requestStream: false; - responseStream: false; requestSerialize: grpc.serialize; requestDeserialize: grpc.deserialize; - responseSerialize: grpc.serialize; - responseDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; } -interface IClientServiceService_ISessionsLockAll extends grpc.MethodDefinition { +interface IClientServiceService_ISessionsLockAll extends grpc.MethodDefinition { path: "/polykey.v1.ClientService/SessionsLockAll"; requestStream: false; responseStream: false; requestSerialize: grpc.serialize; requestDeserialize: grpc.deserialize; - responseSerialize: grpc.serialize; - responseDeserialize: grpc.deserialize; + responseSerialize: grpc.serialize; + responseDeserialize: grpc.deserialize; } interface IClientServiceService_INodesAdd extends grpc.MethodDefinition { path: "/polykey.v1.ClientService/NodesAdd"; @@ -647,9 +637,8 @@ export const ClientServiceService: IClientServiceService; export interface IClientServiceServer extends grpc.UntypedServiceImplementation { agentStatus: grpc.handleUnaryCall; agentStop: grpc.handleUnaryCall; - sessionsUnlock: grpc.handleUnaryCall; - sessionsRefresh: grpc.handleUnaryCall; - sessionsLockAll: grpc.handleUnaryCall; + sessionsUnlock: grpc.handleUnaryCall; + sessionsLockAll: grpc.handleUnaryCall; nodesAdd: grpc.handleUnaryCall; nodesPing: grpc.handleUnaryCall; nodesClaim: grpc.handleUnaryCall; @@ -716,15 +705,12 @@ export interface IClientServiceClient { agentStop(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; agentStop(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; agentStop(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - sessionsUnlock(request: polykey_v1_sessions_sessions_pb.Password, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - sessionsUnlock(request: polykey_v1_sessions_sessions_pb.Password, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - sessionsUnlock(request: polykey_v1_sessions_sessions_pb.Password, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - sessionsRefresh(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - sessionsRefresh(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - sessionsRefresh(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; - sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; - sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; + sessionsUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + sessionsUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + sessionsUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; @@ -897,15 +883,12 @@ export class ClientServiceClient extends grpc.Client implements IClientServiceCl public agentStop(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public agentStop(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public agentStop(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; - public sessionsUnlock(request: polykey_v1_sessions_sessions_pb.Password, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - public sessionsUnlock(request: polykey_v1_sessions_sessions_pb.Password, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - public sessionsUnlock(request: polykey_v1_sessions_sessions_pb.Password, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - public sessionsRefresh(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - public sessionsRefresh(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - public sessionsRefresh(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_sessions_sessions_pb.Token) => void): grpc.ClientUnaryCall; - public sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; - public sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; - public sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.StatusMessage) => void): grpc.ClientUnaryCall; + public sessionsUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public sessionsUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public sessionsUnlock(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; + public sessionsLockAll(request: polykey_v1_utils_utils_pb.EmptyMessage, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; public nodesAdd(request: polykey_v1_nodes_nodes_pb.NodeAddress, metadata: grpc.Metadata, options: Partial, callback: (error: grpc.ServiceError | null, response: polykey_v1_utils_utils_pb.EmptyMessage) => void): grpc.ClientUnaryCall; diff --git a/src/proto/js/polykey/v1/client_service_grpc_pb.js b/src/proto/js/polykey/v1/client_service_grpc_pb.js index 103b234a6..397a11162 100644 --- a/src/proto/js/polykey/v1/client_service_grpc_pb.js +++ b/src/proto/js/polykey/v1/client_service_grpc_pb.js @@ -278,17 +278,6 @@ function deserialize_polykey_v1_sessions_Password(buffer_arg) { return polykey_v1_sessions_sessions_pb.Password.deserializeBinary(new Uint8Array(buffer_arg)); } -function serialize_polykey_v1_sessions_Token(arg) { - if (!(arg instanceof polykey_v1_sessions_sessions_pb.Token)) { - throw new Error('Expected argument of type polykey.v1.sessions.Token'); - } - return Buffer.from(arg.serializeBinary()); -} - -function deserialize_polykey_v1_sessions_Token(buffer_arg) { - return polykey_v1_sessions_sessions_pb.Token.deserializeBinary(new Uint8Array(buffer_arg)); -} - function serialize_polykey_v1_utils_EmptyMessage(arg) { if (!(arg instanceof polykey_v1_utils_utils_pb.EmptyMessage)) { throw new Error('Expected argument of type polykey.v1.utils.EmptyMessage'); @@ -506,34 +495,23 @@ sessionsUnlock: { path: '/polykey.v1.ClientService/SessionsUnlock', requestStream: false, responseStream: false, - requestType: polykey_v1_sessions_sessions_pb.Password, - responseType: polykey_v1_sessions_sessions_pb.Token, - requestSerialize: serialize_polykey_v1_sessions_Password, - requestDeserialize: deserialize_polykey_v1_sessions_Password, - responseSerialize: serialize_polykey_v1_sessions_Token, - responseDeserialize: deserialize_polykey_v1_sessions_Token, - }, - sessionsRefresh: { - path: '/polykey.v1.ClientService/SessionsRefresh', - requestStream: false, - responseStream: false, requestType: polykey_v1_utils_utils_pb.EmptyMessage, - responseType: polykey_v1_sessions_sessions_pb.Token, + responseType: polykey_v1_utils_utils_pb.EmptyMessage, requestSerialize: serialize_polykey_v1_utils_EmptyMessage, requestDeserialize: deserialize_polykey_v1_utils_EmptyMessage, - responseSerialize: serialize_polykey_v1_sessions_Token, - responseDeserialize: deserialize_polykey_v1_sessions_Token, + responseSerialize: serialize_polykey_v1_utils_EmptyMessage, + responseDeserialize: deserialize_polykey_v1_utils_EmptyMessage, }, sessionsLockAll: { path: '/polykey.v1.ClientService/SessionsLockAll', requestStream: false, responseStream: false, requestType: polykey_v1_utils_utils_pb.EmptyMessage, - responseType: polykey_v1_utils_utils_pb.StatusMessage, + responseType: polykey_v1_utils_utils_pb.EmptyMessage, requestSerialize: serialize_polykey_v1_utils_EmptyMessage, requestDeserialize: deserialize_polykey_v1_utils_EmptyMessage, - responseSerialize: serialize_polykey_v1_utils_StatusMessage, - responseDeserialize: deserialize_polykey_v1_utils_StatusMessage, + responseSerialize: serialize_polykey_v1_utils_EmptyMessage, + responseDeserialize: deserialize_polykey_v1_utils_EmptyMessage, }, // Nodes nodesAdd: { diff --git a/src/proto/schemas/polykey/v1/client_service.proto b/src/proto/schemas/polykey/v1/client_service.proto index 03dffd7b3..d27cd8562 100644 --- a/src/proto/schemas/polykey/v1/client_service.proto +++ b/src/proto/schemas/polykey/v1/client_service.proto @@ -20,9 +20,8 @@ service ClientService { rpc AgentStop(polykey.v1.utils.EmptyMessage) returns (polykey.v1.utils.EmptyMessage); // Session - rpc SessionsUnlock (polykey.v1.sessions.Password) returns (polykey.v1.sessions.Token); - rpc SessionsRefresh (polykey.v1.utils.EmptyMessage) returns (polykey.v1.sessions.Token); - rpc SessionsLockAll (polykey.v1.utils.EmptyMessage) returns (polykey.v1.utils.StatusMessage); + rpc SessionsUnlock (polykey.v1.utils.EmptyMessage) returns (polykey.v1.utils.EmptyMessage); + rpc SessionsLockAll (polykey.v1.utils.EmptyMessage) returns (polykey.v1.utils.EmptyMessage); // Nodes rpc NodesAdd(polykey.v1.nodes.NodeAddress) returns (polykey.v1.utils.EmptyMessage); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 2e53f3fc6..7ac87e633 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -47,6 +47,22 @@ async function mkdirExists(fs: FileSystem, path, ...args) { } } +/** + * Checks if a directory is empty + * If the path does not exist, also returns true + */ +async function dirEmpty(fs: FileSystem, path): Promise { + try { + const entries = await fs.promises.readdir(path); + return entries.length === 0; + } catch (e) { + if (e.code === 'ENOENT') { + return false; + } + throw e; + } +} + /** * Test whether a path includes another path * This will return true when path 1 is the same as path 2 @@ -60,15 +76,6 @@ function pathIncludes(p1: string, p2: string): boolean { ); } -function pidIsRunning(pid: number) { - try { - process.kill(pid, 0); - return true; - } catch (e) { - return false; - } -} - async function sleep(ms: number) { return await new Promise((r) => setTimeout(r, ms)); } @@ -93,10 +100,6 @@ function getUnixtime(date: Date = new Date()) { return Math.round(date.getTime() / 1000); } -function getRandomInt(max = Number.MAX_SAFE_INTEGER) { - return Math.floor(Math.random() * max); -} - /** * Poll execution and use condition to accept or reject the results */ @@ -204,13 +207,12 @@ export { getDefaultNodePath, never, mkdirExists, + dirEmpty, pathIncludes, - pidIsRunning, sleep, isEmptyObject, filterEmptyObject, getUnixtime, - getRandomInt, poll, promisify, promise, diff --git a/tests/PolykeyClient.test.ts b/tests/PolykeyClient.test.ts new file mode 100644 index 000000000..8f97b80aa --- /dev/null +++ b/tests/PolykeyClient.test.ts @@ -0,0 +1,84 @@ +import type { SessionToken } from '@/sessions/types'; +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { PolykeyClient, PolykeyAgent } from '@'; +import { Session } from '@/sessions'; +import * as keysUtils from '@/keys/utils'; +import config from '@/config'; +import * as testUtils from './utils'; + +jest + .spyOn(keysUtils, 'generateKeyPair') + .mockImplementation(testUtils.getGlobalKeyPair); +jest + .spyOn(keysUtils, 'generateDeterministicKeyPair') + .mockImplementation(testUtils.getGlobalKeyPair); + +describe('PolykeyClient', () => { + const password = 'password'; + const logger = new Logger('PolykeyClient Test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let dataDir: string; + let nodePath: string; + let pkAgent: PolykeyAgent; + beforeAll(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + nodePath = path.join(dataDir, 'polykey'); + pkAgent = await PolykeyAgent.createPolykeyAgent({ + password, + nodePath, + logger, + }); + }); + afterAll(async () => { + await pkAgent.stop(); + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('create PolykeyClient and connect to PolykeyAgent', async () => { + const pkClient = await PolykeyClient.createPolykeyClient({ + nodeId: pkAgent.keyManager.getNodeId(), + host: pkAgent.grpcServerClient.host, + port: pkAgent.grpcServerClient.port, + nodePath, + fs, + logger, + }); + expect(pkClient.grpcClient.nodeId).toBe(pkAgent.keyManager.getNodeId()); + expect(pkClient.grpcClient.host).toBe(pkAgent.grpcServerClient.host); + expect(pkClient.grpcClient.port).toBe(pkAgent.grpcServerClient.port); + expect(pkClient.grpcClient.secured).toBe(true); + await pkClient.stop(); + }); + test('preserving and destroying session state', async () => { + const session = await Session.createSession({ + sessionTokenPath: path.join(nodePath, config.defaults.tokenBase), + fs, + logger, + }); + await session.writeToken('dummy' as SessionToken); + // Using fresh: true means that any token would be destroyed + const pkClient = await PolykeyClient.createPolykeyClient({ + nodeId: pkAgent.keyManager.getNodeId(), + host: pkAgent.grpcServerClient.host, + port: pkAgent.grpcServerClient.port, + nodePath, + fs, + logger, + fresh: true, + }); + expect(await session.readToken()).toBeUndefined(); + await session.writeToken('abc' as SessionToken); + await pkClient.stop(); + expect(await session.readToken()).toBeDefined(); + await pkClient.destroy(); + expect(await session.readToken()).toBeUndefined(); + }); +}); diff --git a/tests/bin/agent/lock.test.ts b/tests/bin/agent/lock.test.ts new file mode 100644 index 000000000..74475b138 --- /dev/null +++ b/tests/bin/agent/lock.test.ts @@ -0,0 +1,100 @@ +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import prompts from 'prompts'; +import { mocked } from 'ts-jest/utils'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { Session } from '@/sessions'; +import config from '@/config'; +import * as testBinUtils from '../utils'; + +/** + * Mock prompts module which is used prompt for password + */ +jest.mock('prompts'); +const mockedPrompts = mocked(prompts); + +describe('lock', () => { + const logger = new Logger('lock test', LogLevel.WARN, [new StreamHandler()]); + let pkAgentClose; + beforeAll(async () => { + pkAgentClose = await testBinUtils.pkAgent(); + }, global.maxTimeout); + afterAll(async () => { + await pkAgentClose(); + }); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('lock deletes the session token', async () => { + await testBinUtils.pkStdio( + ['agent', 'unlock'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + ); + const { exitCode } = await testBinUtils.pkStdio( + ['agent', 'lock'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + expect(exitCode).toBe(0); + const session = await Session.createSession({ + sessionTokenPath: path.join( + global.binAgentDir, + config.defaults.tokenBase, + ), + fs, + logger, + }); + expect(await session.readToken()).toBeUndefined(); + await session.stop(); + }); + test('lock ensures reauthentication is required', async () => { + const password = global.binAgentPassword; + mockedPrompts.mockClear(); + mockedPrompts.mockImplementation(async (_opts: any) => { + return { password }; + }); + await testBinUtils.pkStdio( + ['agent', 'unlock'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + ); + // Session token is deleted + await testBinUtils.pkStdio( + ['agent', 'lock'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + // Will prompt to reauthenticate + await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + // Prompted for password 1 time + expect(mockedPrompts.mock.calls.length).toBe(1); + mockedPrompts.mockClear(); + }); +}); diff --git a/tests/bin/agent/lockall.test.ts b/tests/bin/agent/lockall.test.ts new file mode 100644 index 000000000..e6a5a3814 --- /dev/null +++ b/tests/bin/agent/lockall.test.ts @@ -0,0 +1,144 @@ +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import prompts from 'prompts'; +import { mocked } from 'ts-jest/utils'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { Session } from '@/sessions'; +import config from '@/config'; +import * as clientErrors from '@/client/errors'; +import * as testBinUtils from '../utils'; + +/** + * Mock prompts module which is used prompt for password + */ +jest.mock('prompts'); +const mockedPrompts = mocked(prompts); + +describe('lockall', () => { + const logger = new Logger('lockall test', LogLevel.WARN, [ + new StreamHandler(), + ]); + let pkAgentClose; + beforeAll(async () => { + pkAgentClose = await testBinUtils.pkAgent(); + }, global.maxTimeout); + afterAll(async () => { + await pkAgentClose(); + }); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('lockall deletes the session token', async () => { + await testBinUtils.pkStdio( + ['agent', 'unlock'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + ); + const { exitCode } = await testBinUtils.pkStdio( + ['agent', 'lockall'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + expect(exitCode).toBe(0); + const session = await Session.createSession({ + sessionTokenPath: path.join( + global.binAgentDir, + config.defaults.tokenBase, + ), + fs, + logger, + }); + expect(await session.readToken()).toBeUndefined(); + await session.stop(); + }); + test('lockall ensures reauthentication is required', async () => { + const password = global.binAgentPassword; + await testBinUtils.pkStdio( + ['agent', 'unlock'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + ); + await testBinUtils.pkStdio( + ['agent', 'lockall'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + // Token is deleted, reauthentication is required + mockedPrompts.mockClear(); + mockedPrompts.mockImplementation(async (_opts: any) => { + return { password }; + }); + await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + // Prompted for password 1 time + expect(mockedPrompts.mock.calls.length).toBe(1); + mockedPrompts.mockClear(); + }); + test('lockall causes old session tokens to fail', async () => { + await testBinUtils.pkStdio( + ['agent', 'unlock'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + ); + const session = await Session.createSession({ + sessionTokenPath: path.join( + global.binAgentDir, + config.defaults.tokenBase, + ), + fs, + logger, + }); + const token = await session.readToken(); + await session.stop(); + await testBinUtils.pkStdio( + ['agent', 'lockall'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + ); + // Old token is invalid + const { exitCode, stderr } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + PK_TOKEN: token, + }, + global.binAgentDir, + ); + testBinUtils.expectProcessError( + exitCode, + stderr, + new clientErrors.ErrorClientAuthDenied(), + ); + }); +}); diff --git a/tests/bin/agent/status.test.ts b/tests/bin/agent/status.test.ts index c5daa9fbf..4c31502e8 100644 --- a/tests/bin/agent/status.test.ts +++ b/tests/bin/agent/status.test.ts @@ -11,14 +11,7 @@ describe('status', () => { const logger = new Logger('status test', LogLevel.WARN, [ new StreamHandler(), ]); - let pkAgentClose; let dataDir: string; - beforeAll(async () => { - pkAgentClose = await testBinUtils.pkAgent(); - }, global.maxTimeout); - afterAll(async () => { - await pkAgentClose(); - }); beforeEach(async () => { dataDir = await fs.promises.mkdtemp( path.join(os.tmpdir(), 'polykey-test-'), @@ -30,98 +23,6 @@ describe('status', () => { recursive: true, }); }); - test('status on LIVE agent', async () => { - const status = new Status({ - statusPath: path.join(global.binAgentDir, config.defaults.statusBase), - fs, - logger, - }); - const statusInfo = (await status.readStatus())!; - const { exitCode, stdout } = await testBinUtils.pkStdio( - ['agent', 'status', '--format', 'json', '--verbose'], - { - PK_NODE_PATH: global.binAgentDir, - PK_PASSWORD: global.binAgentPassword, - }, - global.binAgentDir, - ); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toMatchObject({ - status: 'LIVE', - pid: expect.any(Number), - nodeId: statusInfo.data.nodeId, - clientHost: statusInfo.data.clientHost, - clientPort: statusInfo.data.clientPort, - ingressHost: statusInfo.data.ingressHost, - ingressPort: statusInfo.data.ingressPort, - egressHost: expect.any(String), - egressPort: expect.any(Number), - agentHost: expect.any(String), - agentPort: expect.any(Number), - proxyHost: expect.any(String), - proxyPort: expect.any(Number), - rootPublicKeyPem: expect.any(String), - rootCertPem: expect.any(String), - rootCertChainPem: expect.any(String), - }); - }); - test('status on remote LIVE agent', async () => { - const passwordPath = path.join(dataDir, 'password'); - await fs.promises.writeFile(passwordPath, global.binAgentPassword); - const status = new Status({ - statusPath: path.join(global.binAgentDir, config.defaults.statusBase), - fs, - logger, - }); - const statusInfo = (await status.readStatus())!; - const { exitCode, stdout } = await testBinUtils.pkStdio([ - 'agent', - 'status', - '--password-file', - passwordPath, - '--node-id', - statusInfo.data.nodeId, - '--client-host', - statusInfo.data.clientHost, - '--client-port', - statusInfo.data.clientPort.toString(), - '--format', - 'json', - '--verbose', - ]); - expect(exitCode).toBe(0); - expect(JSON.parse(stdout)).toMatchObject({ - status: 'LIVE', - pid: expect.any(Number), - nodeId: statusInfo.data.nodeId, - clientHost: statusInfo.data.clientHost, - clientPort: statusInfo.data.clientPort, - ingressHost: statusInfo.data.ingressHost, - ingressPort: statusInfo.data.ingressPort, - egressHost: expect.any(String), - egressPort: expect.any(Number), - agentHost: expect.any(String), - agentPort: expect.any(Number), - proxyHost: expect.any(String), - proxyPort: expect.any(Number), - rootPublicKeyPem: expect.any(String), - rootCertPem: expect.any(String), - rootCertChainPem: expect.any(String), - }); - }); - test('status on missing agent', async () => { - const { exitCode, stderr } = await testBinUtils.pkStdio( - ['agent', 'status', '--verbose'], - { - PK_NODE_PATH: path.join(dataDir, 'polykey'), - }, - ); - testBinUtils.expectProcessError( - exitCode, - stderr, - new binErrors.ErrorCLIStatusMissing(), - ); - }); test( 'status on STARTING, STOPPING, DEAD agent', async () => { @@ -188,4 +89,105 @@ describe('status', () => { }, global.defaultTimeout * 2, ); + test('status on missing agent', async () => { + const { exitCode, stderr } = await testBinUtils.pkStdio( + ['agent', 'status', '--verbose'], + { + PK_NODE_PATH: path.join(dataDir, 'polykey'), + }, + ); + testBinUtils.expectProcessError( + exitCode, + stderr, + new binErrors.ErrorCLIStatusMissing(), + ); + }); + describe('status with global agent', () => { + let pkAgentClose; + beforeAll(async () => { + pkAgentClose = await testBinUtils.pkAgent(); + }, global.maxTimeout); + afterAll(async () => { + await pkAgentClose(); + }); + test('status on LIVE agent', async () => { + const status = new Status({ + statusPath: path.join(global.binAgentDir, config.defaults.statusBase), + fs, + logger, + }); + const statusInfo = (await status.readStatus())!; + const { exitCode, stdout } = await testBinUtils.pkStdio( + ['agent', 'status', '--format', 'json', '--verbose'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + ); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toMatchObject({ + status: 'LIVE', + pid: expect.any(Number), + nodeId: statusInfo.data.nodeId, + clientHost: statusInfo.data.clientHost, + clientPort: statusInfo.data.clientPort, + ingressHost: statusInfo.data.ingressHost, + ingressPort: statusInfo.data.ingressPort, + egressHost: expect.any(String), + egressPort: expect.any(Number), + agentHost: expect.any(String), + agentPort: expect.any(Number), + proxyHost: expect.any(String), + proxyPort: expect.any(Number), + rootPublicKeyPem: expect.any(String), + rootCertPem: expect.any(String), + rootCertChainPem: expect.any(String), + }); + }); + test('status on remote LIVE agent', async () => { + const passwordPath = path.join(dataDir, 'password'); + await fs.promises.writeFile(passwordPath, global.binAgentPassword); + const status = new Status({ + statusPath: path.join(global.binAgentDir, config.defaults.statusBase), + fs, + logger, + }); + const statusInfo = (await status.readStatus())!; + const { exitCode, stdout } = await testBinUtils.pkStdio([ + 'agent', + 'status', + '--password-file', + passwordPath, + '--node-id', + statusInfo.data.nodeId, + '--client-host', + statusInfo.data.clientHost, + '--client-port', + statusInfo.data.clientPort.toString(), + '--format', + 'json', + '--verbose', + ]); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toMatchObject({ + status: 'LIVE', + pid: expect.any(Number), + nodeId: statusInfo.data.nodeId, + clientHost: statusInfo.data.clientHost, + clientPort: statusInfo.data.clientPort, + ingressHost: statusInfo.data.ingressHost, + ingressPort: statusInfo.data.ingressPort, + egressHost: expect.any(String), + egressPort: expect.any(Number), + agentHost: expect.any(String), + agentPort: expect.any(Number), + proxyHost: expect.any(String), + proxyPort: expect.any(Number), + rootPublicKeyPem: expect.any(String), + rootCertPem: expect.any(String), + rootCertChainPem: expect.any(String), + }); + }); + }); }); diff --git a/tests/bin/agent/stop.test.ts b/tests/bin/agent/stop.test.ts index 8bf594171..889b64590 100644 --- a/tests/bin/agent/stop.test.ts +++ b/tests/bin/agent/stop.test.ts @@ -5,6 +5,8 @@ import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { Status } from '@/status'; import config from '@/config'; import * as binErrors from '@/bin/errors'; +import * as clientErrors from '@/client/errors'; +import { sleep } from '@/utils'; import * as testBinUtils from '../utils'; describe('stop', () => { @@ -174,4 +176,57 @@ describe('stop', () => { }, global.defaultTimeout * 2, ); + test( + 'stopping while unauthenticated does not stop', + async () => { + const password = 'abc123'; + await testBinUtils.pkStdio( + [ + 'agent', + 'start', + // 1024 is the smallest size and is faster to start + '--root-key-pair-bits', + '1024', + ], + { + PK_NODE_PATH: path.join(dataDir, 'polykey'), + PK_PASSWORD: password, + }, + dataDir, + ); + const status = new Status({ + statusPath: path.join(dataDir, 'polykey', config.defaults.statusBase), + fs, + logger, + }); + const { exitCode, stderr } = await testBinUtils.pkStdio( + ['agent', 'stop'], + { + PK_NODE_PATH: path.join(dataDir, 'polykey'), + PK_PASSWORD: 'wrong password', + }, + dataDir, + ); + testBinUtils.expectProcessError( + exitCode, + stderr, + new clientErrors.ErrorClientAuthDenied(), + ); + // Should still be LIVE + await sleep(500); + const statusInfo = await status.readStatus(); + expect(statusInfo).toBeDefined(); + expect(statusInfo?.status).toBe('LIVE'); + await testBinUtils.pkStdio( + ['agent', 'stop'], + { + PK_NODE_PATH: path.join(dataDir, 'polykey'), + PK_PASSWORD: password, + }, + dataDir, + ); + await status.waitFor('DEAD'); + }, + global.defaultTimeout * 2, + ); }); diff --git a/tests/bin/agent/unlock.test.ts b/tests/bin/agent/unlock.test.ts new file mode 100644 index 000000000..3cabdcd3e --- /dev/null +++ b/tests/bin/agent/unlock.test.ts @@ -0,0 +1,74 @@ +import os from 'os'; +import path from 'path'; +import fs from 'fs'; +import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; +import { Session } from '@/sessions'; +import config from '@/config'; +import * as testBinUtils from '../utils'; + +describe('unlock', () => { + const logger = new Logger('lock test', LogLevel.WARN, [new StreamHandler()]); + let pkAgentClose; + beforeAll(async () => { + pkAgentClose = await testBinUtils.pkAgent(); + }, global.maxTimeout); + afterAll(async () => { + await pkAgentClose(); + }); + let dataDir: string; + beforeEach(async () => { + dataDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), 'polykey-test-'), + ); + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, + }); + }); + test('unlock acquires session token', async () => { + // Fresh session, to delete the token + const session = await Session.createSession({ + sessionTokenPath: path.join( + global.binAgentDir, + config.defaults.tokenBase, + ), + fs, + logger, + fresh: true, + }); + let exitCode, stdout; + ({ exitCode, stdout } = await testBinUtils.pkStdio( + ['agent', 'unlock'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + )); + expect(exitCode).toBe(0); + // Run command without password + ({ exitCode, stdout } = await testBinUtils.pkStdio( + ['agent', 'status', '--format', 'json'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toMatchObject({ status: 'LIVE' }); + // Run command with PK_TOKEN + ({ exitCode, stdout } = await testBinUtils.pkStdio( + ['agent', 'status', '--format', 'json'], + { + PK_NODE_PATH: global.binAgentDir, + PK_TOKEN: await session.readToken(), + }, + global.binAgentDir, + )); + expect(exitCode).toBe(0); + expect(JSON.parse(stdout)).toMatchObject({ status: 'LIVE' }); + await session.stop(); + }); +}); diff --git a/tests/bin/bootstrap.test.ts b/tests/bin/bootstrap.test.ts index beae34f75..9b557f794 100644 --- a/tests/bin/bootstrap.test.ts +++ b/tests/bin/bootstrap.test.ts @@ -51,130 +51,138 @@ describe('bootstrap', () => { recoveryCode.split(' ').length === 24, ).toBe(true); }, - global.defaultTimeout, + global.defaultTimeout * 2, ); - test('bootstrapping occupied node state', async () => { - const password = 'password'; - await fs.promises.mkdir(path.join(dataDir, 'polykey')); - await fs.promises.writeFile(path.join(dataDir, 'polykey', 'test'), ''); - let exitCode, stdout, stderr; - ({ exitCode, stdout, stderr } = await testBinUtils.pkStdio( - [ - 'bootstrap', - '--node-path', - path.join(dataDir, 'polykey'), - '--root-key-pair-bits', - '1024', - '--verbose', - ], - { - PK_PASSWORD: password, - }, - dataDir, - )); - const errorBootstrapExistingState = - new bootstrapErrors.ErrorBootstrapExistingState(); - expect(exitCode).toBe(errorBootstrapExistingState.exitCode); - const stdErrLine = stderr.trim().split('\n').pop(); - const eOutput = binUtils - .outputFormatter({ - type: 'error', - name: errorBootstrapExistingState.name, - description: errorBootstrapExistingState.description, - message: errorBootstrapExistingState.message, - }) - .trim(); - expect(stdErrLine).toBe(eOutput); - ({ exitCode, stdout, stderr } = await testBinUtils.pkStdio( - [ - 'bootstrap', - '--node-path', - path.join(dataDir, 'polykey'), - '--root-key-pair-bits', - '1024', - '--fresh', - '--verbose', - ], - { - PK_PASSWORD: password, - }, - dataDir, - )); - expect(exitCode).toBe(0); - const recoveryCode = stdout.trim(); - expect( - recoveryCode.split(' ').length === 12 || - recoveryCode.split(' ').length === 24, - ).toBe(true); - }); - test('concurrent bootstrapping are coalesced', async () => { - const password = 'password'; - const [bootstrapProcess1, bootstrapProcess2] = await Promise.all([ - testBinUtils.pkSpawn( - ['bootstrap', '--root-key-pair-bits', '1024', '--verbose'], + test( + 'bootstrapping occupied node state', + async () => { + const password = 'password'; + await fs.promises.mkdir(path.join(dataDir, 'polykey')); + await fs.promises.writeFile(path.join(dataDir, 'polykey', 'test'), ''); + let exitCode, stdout, stderr; + ({ exitCode, stdout, stderr } = await testBinUtils.pkStdio( + [ + 'bootstrap', + '--node-path', + path.join(dataDir, 'polykey'), + '--root-key-pair-bits', + '1024', + '--verbose', + ], { - PK_NODE_PATH: path.join(dataDir, 'polykey'), PK_PASSWORD: password, }, dataDir, - logger.getChild('bootstrapProcess1'), - ), - testBinUtils.pkSpawn( - ['bootstrap', '--root-key-pair-bits', '1024', '--verbose'], + )); + const errorBootstrapExistingState = + new bootstrapErrors.ErrorBootstrapExistingState(); + expect(exitCode).toBe(errorBootstrapExistingState.exitCode); + const stdErrLine = stderr.trim().split('\n').pop(); + const eOutput = binUtils + .outputFormatter({ + type: 'error', + name: errorBootstrapExistingState.name, + description: errorBootstrapExistingState.description, + message: errorBootstrapExistingState.message, + }) + .trim(); + expect(stdErrLine).toBe(eOutput); + ({ exitCode, stdout, stderr } = await testBinUtils.pkStdio( + [ + 'bootstrap', + '--node-path', + path.join(dataDir, 'polykey'), + '--root-key-pair-bits', + '1024', + '--fresh', + '--verbose', + ], { - PK_NODE_PATH: path.join(dataDir, 'polykey'), PK_PASSWORD: password, }, dataDir, - logger.getChild('bootstrapProcess2'), - ), - ]); - // These will be the last line of STDERR - // The readline library will automatically trim off newlines - let stdErrLine1; - let stdErrLine2; - const rlErr1 = readline.createInterface(bootstrapProcess1.stderr!); - const rlErr2 = readline.createInterface(bootstrapProcess2.stderr!); - rlErr1.on('line', (l) => { - stdErrLine1 = l; - }); - rlErr2.on('line', (l) => { - stdErrLine2 = l; - }); - const [index, exitCode, signal] = await new Promise< - [number, number | null, NodeJS.Signals | null] - >((resolve) => { - bootstrapProcess1.once('exit', (code, signal) => { - resolve([0, code, signal]); + )); + expect(exitCode).toBe(0); + const recoveryCode = stdout.trim(); + expect( + recoveryCode.split(' ').length === 12 || + recoveryCode.split(' ').length === 24, + ).toBe(true); + }, + global.defaultTimeout * 2, + ); + test( + 'concurrent bootstrapping are coalesced', + async () => { + const password = 'password'; + const [bootstrapProcess1, bootstrapProcess2] = await Promise.all([ + testBinUtils.pkSpawn( + ['bootstrap', '--root-key-pair-bits', '1024', '--verbose'], + { + PK_NODE_PATH: path.join(dataDir, 'polykey'), + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('bootstrapProcess1'), + ), + testBinUtils.pkSpawn( + ['bootstrap', '--root-key-pair-bits', '1024', '--verbose'], + { + PK_NODE_PATH: path.join(dataDir, 'polykey'), + PK_PASSWORD: password, + }, + dataDir, + logger.getChild('bootstrapProcess2'), + ), + ]); + // These will be the last line of STDERR + // The readline library will automatically trim off newlines + let stdErrLine1; + let stdErrLine2; + const rlErr1 = readline.createInterface(bootstrapProcess1.stderr!); + const rlErr2 = readline.createInterface(bootstrapProcess2.stderr!); + rlErr1.on('line', (l) => { + stdErrLine1 = l; }); - bootstrapProcess2.once('exit', (code, signal) => { - resolve([1, code, signal]); + rlErr2.on('line', (l) => { + stdErrLine2 = l; }); - }); - const errorStatusLocked = new statusErrors.ErrorStatusLocked(); - expect(exitCode).toBe(errorStatusLocked.exitCode); - expect(signal).toBe(null); - const eOutput = binUtils - .outputFormatter({ - type: 'error', - name: errorStatusLocked.name, - description: errorStatusLocked.description, - message: errorStatusLocked.message, - }) - .trim(); - // It's either the first or second process - if (index === 0) { - expect(stdErrLine1).toBeDefined(); - expect(stdErrLine1).toBe(eOutput); - const [exitCode] = await testBinUtils.processExit(bootstrapProcess2); - expect(exitCode).toBe(0); - } else if (index === 1) { - expect(stdErrLine2).toBeDefined(); - expect(stdErrLine2).toBe(eOutput); - const [exitCode] = await testBinUtils.processExit(bootstrapProcess1); - expect(exitCode).toBe(0); - } - }); + const [index, exitCode, signal] = await new Promise< + [number, number | null, NodeJS.Signals | null] + >((resolve) => { + bootstrapProcess1.once('exit', (code, signal) => { + resolve([0, code, signal]); + }); + bootstrapProcess2.once('exit', (code, signal) => { + resolve([1, code, signal]); + }); + }); + const errorStatusLocked = new statusErrors.ErrorStatusLocked(); + expect(exitCode).toBe(errorStatusLocked.exitCode); + expect(signal).toBe(null); + const eOutput = binUtils + .outputFormatter({ + type: 'error', + name: errorStatusLocked.name, + description: errorStatusLocked.description, + message: errorStatusLocked.message, + }) + .trim(); + // It's either the first or second process + if (index === 0) { + expect(stdErrLine1).toBeDefined(); + expect(stdErrLine1).toBe(eOutput); + const [exitCode] = await testBinUtils.processExit(bootstrapProcess2); + expect(exitCode).toBe(0); + } else if (index === 1) { + expect(stdErrLine2).toBeDefined(); + expect(stdErrLine2).toBe(eOutput); + const [exitCode] = await testBinUtils.processExit(bootstrapProcess1); + expect(exitCode).toBe(0); + } + }, + global.defaultTimeout * 2, + ); test( 'bootstrap when interrupted, requires fresh on next bootstrap', async () => { diff --git a/tests/bin/keys.test.ts b/tests/bin/keys.test.ts index 0e79fe64b..970eb9348 100644 --- a/tests/bin/keys.test.ts +++ b/tests/bin/keys.test.ts @@ -154,7 +154,7 @@ describe('CLI keys', () => { const passPath = path.join(dataDir, 'passwordNew'); await fs.promises.writeFile(passPath, 'password-new'); - command = ['keys', 'renew', '-np', nodePath, passPath]; + command = ['keys', 'renew', '-np', nodePath, '-pnf', passPath]; const result = await utils.pkStdio([...command], {}, dataDir); expect(result.exitCode).toBe(0); @@ -183,7 +183,7 @@ describe('CLI keys', () => { const passPath = path.join(dataDir, 'passwordNewNew'); await fs.promises.writeFile(passPath, 'password-new-new'); - command = ['keys', 'reset', '-np', nodePath, passPath]; + command = ['keys', 'reset', '-np', nodePath, '-pnf', passPath]; const result = await utils.pkStdio([...command], {}, dataDir); expect(result.exitCode).toBe(0); @@ -211,7 +211,7 @@ describe('CLI keys', () => { const passPath = path.join(dataDir, 'passwordChange'); await fs.promises.writeFile(passPath, 'password-change'); - command = ['keys', 'password', '-np', nodePath, passPath]; + command = ['keys', 'password', '-np', nodePath, '-pnf', passPath]; const result2 = await utils.pkStdio([...command], {}, dataDir); expect(result2.exitCode).toBe(0); diff --git a/tests/bin/nodes.test.ts b/tests/bin/nodes.test.ts index 3e969f458..f5fb736df 100644 --- a/tests/bin/nodes.test.ts +++ b/tests/bin/nodes.test.ts @@ -15,19 +15,6 @@ jest.mock('@/keys/utils', () => ({ jest.requireActual('@/keys/utils').generateKeyPair, })); -/** - * This test file has been optimised to use only one instance of PolykeyAgent where posible. - * Setting up the PolykeyAgent has been done in a beforeAll block. - * Keep this in mind when adding or editing tests. - * Any side effects need to be undone when the test has completed. - * Preferably within a `afterEach()` since any cleanup will be skipped inside a failing test. - * - * - left over state can cause a test to fail in certain cases. - * - left over state can cause similar tests to succeed when they should fail. - * - starting or stopping the agent within tests should be done on a new instance of the polykey agent. - * - when in doubt test each modified or added test on it's own as well as the whole file. - * - Looking into adding a way to safely clear each domain's DB information with out breaking modules. - */ describe('CLI Nodes', () => { const password = 'password'; const logger = new Logger('pkStdio Test', LogLevel.WARN, [ @@ -362,7 +349,6 @@ describe('CLI Nodes', () => { ]); const result = await testUtils.pkStdio(commands, {}, dataDir); expect(result.exitCode).toBe(0); - expect(result.stdout).toContain('Added node'); // Checking if node was added. const res = await polykeyAgent.nodeManager.getNode(validNodeId); diff --git a/tests/bin/notifications.test.ts b/tests/bin/notifications.test.ts index 357f92e00..3ccd1070f 100644 --- a/tests/bin/notifications.test.ts +++ b/tests/bin/notifications.test.ts @@ -17,19 +17,6 @@ jest.mock('@/keys/utils', () => ({ jest.requireActual('@/keys/utils').generateKeyPair, })); -/** - * This test file has been optimised to use only one instance of PolykeyAgent where posible. - * Setting up the PolykeyAgent has been done in a beforeAll block. - * Keep this in mind when adding or editing tests. - * Any side effects need to be undone when the test has completed. - * Preferably within a `afterEach()` since any cleanup will be skipped inside a failing test. - * - * - left over state can cause a test to fail in certain cases. - * - left over state can cause similar tests to succeed when they should fail. - * - starting or stopping the agent within tests should be done on a new instance of the polykey agent. - * - when in doubt test each modified or added test on it's own as well as the whole file. - * - Looking into adding a way to safely clear each domain's DB information with out breaking modules. - */ describe('CLI Notifications', () => { const password = 'password'; const logger = new Logger('pkStdio Test', LogLevel.WARN, [ @@ -123,7 +110,6 @@ describe('CLI Notifications', () => { const commands = genCommandsSender(['send', receiverNodeId, 'msg']); const result = await testUtils.pkStdio(commands, {}, senderDataDir); expect(result.exitCode).toBe(0); // Succeeds - expect(result.stdout).toContain('msg'); const notifications = await receiverPolykeyAgent.notificationsManager.readNotifications(); expect(notifications[0].data).toEqual({ @@ -139,7 +125,6 @@ describe('CLI Notifications', () => { const commands = genCommandsSender(['send', receiverNodeId, 'msg']); const result = await testUtils.pkStdio(commands, {}, senderDataDir); expect(result.exitCode).toBe(0); // Succeeds - expect(result.stdout).toContain('msg'); const notifications = await receiverPolykeyAgent.notificationsManager.readNotifications(); expect(notifications).toEqual([]); // Notification should be sent but not received diff --git a/tests/bin/sessions.test.ts b/tests/bin/sessions.test.ts index 96741f898..6cb95c393 100644 --- a/tests/bin/sessions.test.ts +++ b/tests/bin/sessions.test.ts @@ -1,215 +1,183 @@ -import type { VaultName } from '@/vaults/types'; -import type { SessionToken } from '@/sessions/types'; +/** + * There is no command call sessions + * This is just for testing the CLI Authentication Retry Loop + * @module + */ import os from 'os'; import path from 'path'; import fs from 'fs'; -import lock from 'fd-lock'; +import { mocked } from 'ts-jest/utils'; +import prompts from 'prompts'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import PolykeyAgent from '@/PolykeyAgent'; +import { Session } from '@/sessions'; import { sleep } from '@/utils'; -import * as testUtils from './utils'; - -jest.mock('@/keys/utils', () => ({ - ...jest.requireActual('@/keys/utils'), - generateDeterministicKeyPair: - jest.requireActual('@/keys/utils').generateKeyPair, -})); +import config from '@/config'; +import * as clientErrors from '@/client/errors'; +import * as testBinUtils from './utils'; /** - * This test file has been optimised to use only one instance of PolykeyAgent where posible. - * Setting up the PolykeyAgent has been done in a beforeAll block. - * Keep this in mind when adding or editing tests. - * Any side effects need to be undone when the test has completed. - * Preferably within a `afterEach()` since any cleanup will be skipped inside a failing test. - * - * - left over state can cause a test to fail in certain cases. - * - left over state can cause similar tests to succeed when they should fail. - * - starting or stopping the agent within tests should be done on a new instance of the polykey agent. - * - when in doubt test each modified or added test on it's own as well as the whole file. - * - Looking into adding a way to safely clear each domain's DB information with out breaking modules. + * Mock prompts module which is used prompt for password */ +jest.mock('prompts'); +const mockedPrompts = mocked(prompts); -describe('Session Token Refreshing', () => { - const logger = new Logger('pkStdio Test', LogLevel.WARN, [ +describe('CLI Sessions', () => { + const logger = new Logger('sessions test', LogLevel.WARN, [ new StreamHandler(), ]); - let dataDir: string; - let nodePath: string; - let passwordFile: string; - let sessionFile: string; - let polykeyAgent: PolykeyAgent; - - let tokenBuffer: Buffer; - let token: SessionToken; - let command: string[]; - const vaultName = 'TestVault' as VaultName; - + let pkAgentClose; beforeAll(async () => { - // This handles the expensive setting up of the polykey agent. + pkAgentClose = await testBinUtils.pkAgent(); + }, global.maxTimeout); + afterAll(async () => { + await pkAgentClose(); + }); + let dataDir: string; + beforeEach(async () => { dataDir = await fs.promises.mkdtemp( path.join(os.tmpdir(), 'polykey-test-'), ); - nodePath = path.join(dataDir, 'keynode'); - command = ['vaults', 'list', '-np', nodePath]; - passwordFile = path.join(dataDir, 'passwordFile'); - sessionFile = path.join(nodePath, 'token'); - await fs.promises.writeFile(passwordFile, 'password'); - polykeyAgent = await PolykeyAgent.createPolykeyAgent({ - password: 'password', - nodePath: nodePath, - logger: logger, + }); + afterEach(async () => { + await fs.promises.rm(dataDir, { + force: true, + recursive: true, }); - await polykeyAgent.vaultManager.createVault(vaultName); }); - - afterAll(async () => { - await polykeyAgent.stop(); - await polykeyAgent.destroy(); - await fs.promises.rmdir(dataDir, { recursive: true }); + test('serial commands refresh the session token', async () => { + const session = await Session.createSession({ + sessionTokenPath: path.join( + global.binAgentDir, + config.defaults.tokenBase, + ), + fs, + logger, + }); + let exitCode; + ({ exitCode } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + )); + expect(exitCode).toBe(0); + const token1 = await session.readToken(); + // Tokens are not nonces + // Wait at least 1 second + // To ensure that the next token has a new expiry + await sleep(1100); + ({ exitCode } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: global.binAgentPassword, + }, + global.binAgentDir, + )); + expect(exitCode).toBe(0); + const token2 = await session.readToken(); + expect(token1).not.toBe(token2); + await session.stop(); }); - - test('Process should store session token in session file', async () => { - // Agent has not been unlocked yet - const result = await testUtils.pkStdio( - command, - { PK_PASSWORD: 'password' }, - dataDir, + test('unattended commands with invalid authentication should fail', async () => { + let exitCode, stderr; + // Password and Token set + ({ exitCode, stderr } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: 'invalid', + PK_TOKEN: 'token', + }, + global.binAgentDir, + )); + testBinUtils.expectProcessError( + exitCode, + stderr, + new clientErrors.ErrorClientAuthDenied(), + ); + // Password set + ({ exitCode, stderr } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: 'invalid', + PK_TOKEN: undefined, + }, + global.binAgentDir, + )); + testBinUtils.expectProcessError( + exitCode, + stderr, + new clientErrors.ErrorClientAuthDenied(), + ); + // Token set + ({ exitCode, stderr } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + PK_PASSWORD: undefined, + PK_TOKEN: 'token', + }, + global.binAgentDir, + )); + testBinUtils.expectProcessError( + exitCode, + stderr, + new clientErrors.ErrorClientAuthDenied(), ); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain(vaultName); - - const buff = await fs.promises.readFile(sessionFile); - const newToken = buff.toString() as SessionToken; - expect( - async () => await polykeyAgent.sessionManager.verifyToken(newToken), - ).not.toThrow(); }); - - describe('After session has been unlocked', () => { - beforeAll(async () => { - // Authorize session - await testUtils.pkStdio( - ['agent', 'unlock', '-np', nodePath, '--password-file', passwordFile], - {}, - dataDir, - ); - }, global.polykeyStartupTimeout); - - test('Process should refresh the session token', async () => { - tokenBuffer = await fs.promises.readFile(sessionFile); - token = tokenBuffer.toString() as SessionToken; - const prevToken = token; - - // At least 1 second of delay - // Expiry time resolution is in seconds - await sleep(1100); - const result = await testUtils.pkStdio(command, {}, dataDir); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain(vaultName); - - const buff = await fs.promises.readFile(sessionFile); - const newToken = buff.toString() as SessionToken; - expect( - async () => await polykeyAgent.sessionManager.verifyToken(newToken), - ).not.toThrow(); - // Make sure the first and second tokens are not the same - expect(newToken).not.toEqual(prevToken); - }); - - test('Serial processes should refresh the session token', async () => { - let result = await testUtils.pkStdio(command, {}, dataDir); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain(vaultName); - - tokenBuffer = await fs.promises.readFile(sessionFile); - const token1 = tokenBuffer.toString() as SessionToken; - expect( - async () => await polykeyAgent.sessionManager.verifyToken(token1), - ).not.toThrow(); - - // At least 1 second of delay - // Expiry time resolution is in seconds - await sleep(1100); - result = await testUtils.pkStdio(command, {}, dataDir); - expect(result.exitCode).toBe(0); - expect(result.stdout).toContain(vaultName); - - tokenBuffer = await fs.promises.readFile(sessionFile); - const token2 = tokenBuffer.toString() as SessionToken; - expect( - async () => await polykeyAgent.sessionManager.verifyToken(token2), - ).not.toThrow(); - - // Make sure the first and second tokens are not the same - expect(token1).not.toEqual(token2); - }); - - test( - 'Failing processes should unlock the session file', - async () => { - const result = await testUtils.pkStdio( - ['vaults', 'delete', 'NotAVault', '-np', nodePath], - {}, - dataDir, - ); - expect(result.exitCode).not.toBe(0); - - tokenBuffer = await fs.promises.readFile(sessionFile); - token = tokenBuffer.toString() as SessionToken; - expect( - async () => await polykeyAgent.sessionManager.verifyToken(token), - ).not.toThrow(); - - // Try to lock the session file to ensure it's unlocked - const fd = fs.openSync(sessionFile, 'r'); - expect(lock(fd)).toBeTruthy(); - lock.unlock(fd); - fs.closeSync(fd); + test('prompt for password to authenticate attended commands', async () => { + const password = global.binAgentPassword; + await testBinUtils.pkStdio( + ['agent', 'lock'], + { + PK_NODE_PATH: global.binAgentDir, }, - global.failedConnectionTimeout, + global.binAgentDir, ); - - test('Parallel processes should not refresh the session token', async () => { - let tokenP1 = 'token1' as SessionToken; - let tokenP2 = 'token2' as SessionToken; - - tokenBuffer = await fs.promises.readFile(sessionFile); - const prevTokenParallel = tokenBuffer.toString() as SessionToken; - - async function runListCommand(): Promise { - // At least 1 second of delay - // Expiry time resolution is in seconds - await sleep(1000); - await testUtils.pkStdio(command, {}, dataDir); - const buffer = await fs.promises.readFile(sessionFile); - return buffer.toString() as SessionToken; - } - - [tokenP1, tokenP2] = await Promise.all([ - runListCommand(), - runListCommand(), - ]); - - // Verify both tokens - expect( - async () => await polykeyAgent.sessionManager.verifyToken(tokenP1), - ).not.toThrow(); - expect( - async () => await polykeyAgent.sessionManager.verifyToken(tokenP2), - ).not.toThrow(); - - // Check that both commands were completed - expect(tokenP1).not.toEqual('token1'); - expect(tokenP2).not.toEqual('token2'); - - // Check that the session token was refreshed exactly one time - if (tokenP1 === prevTokenParallel) { - expect(tokenP2).not.toEqual(prevTokenParallel); - } else if (tokenP2 === prevTokenParallel) { - expect(tokenP1).not.toEqual(prevTokenParallel); - } else { - expect(tokenP1).toEqual(tokenP2); - } + mockedPrompts.mockClear(); + mockedPrompts.mockImplementation(async (_opts: any) => { + return { password }; }); + const { exitCode } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + expect(exitCode).toBe(0); + // Prompted for password 1 time + expect(mockedPrompts.mock.calls.length).toBe(1); + mockedPrompts.mockClear(); + }); + test('re-prompts for password if unable to authenticate command', async () => { + await testBinUtils.pkStdio( + ['agent', 'lock'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + const validPassword = global.binAgentPassword; + const invalidPassword = 'invalid'; + mockedPrompts.mockClear(); + mockedPrompts + .mockResolvedValueOnce({ password: invalidPassword }) + .mockResolvedValue({ password: validPassword }); + const { exitCode } = await testBinUtils.pkStdio( + ['agent', 'status'], + { + PK_NODE_PATH: global.binAgentDir, + }, + global.binAgentDir, + ); + expect(exitCode).toBe(0); + // Prompted for password 2 times + expect(mockedPrompts.mock.calls.length).toBe(2); + mockedPrompts.mockClear(); }); }); diff --git a/tests/bin/utils.ts b/tests/bin/utils.ts index f196e6157..d18be222b 100644 --- a/tests/bin/utils.ts +++ b/tests/bin/utils.ts @@ -127,7 +127,10 @@ async function pkExec( }> { cwd = cwd ?? (await fs.promises.mkdtemp(path.join(os.tmpdir(), 'polykey-test-'))); - env = { ...process.env, ...env }; + env = { + ...process.env, + ...env, + }; const tsConfigPath = path.resolve( path.join(global.projectDir, 'tsconfig.json'), ); @@ -145,6 +148,8 @@ async function pkExec( tsConfigPath, '--require', tsConfigPathsRegisterPath, + '--compiler', + 'typescript-cached-transpile', '--transpile-only', polykeyPath, ...args, @@ -186,7 +191,10 @@ async function pkSpawn( ): Promise { cwd = cwd ?? (await fs.promises.mkdtemp(path.join(os.tmpdir(), 'polykey-test-'))); - env = { ...process.env, ...env }; + env = { + ...process.env, + ...env, + }; const tsConfigPath = path.resolve( path.join(global.projectDir, 'tsconfig.json'), ); @@ -203,6 +211,8 @@ async function pkSpawn( tsConfigPath, '--require', tsConfigPathsRegisterPath, + '--compiler', + 'typescript-cached-transpile', '--transpile-only', polykeyPath, ...args, @@ -243,7 +253,10 @@ async function pkExpect({ }> { cwd = cwd ?? (await fs.promises.mkdtemp(path.join(os.tmpdir(), 'polykey-test-'))); - env = { ...process.env, ...env }; + env = { + ...process.env, + ...env, + }; const tsConfigPath = path.resolve( path.join(global.projectDir, 'tsconfig.json'), ); @@ -261,6 +274,8 @@ async function pkExpect({ tsConfigPath, '--require', tsConfigPathsRegisterPath, + '--compiler', + 'typescript-cached-transpile', '--transpile-only', polykeyPath, ...args, @@ -297,6 +312,10 @@ async function pkExpect({ * Uses fd-lock to serialise access to the pkAgent * This means all test modules using this will be serialised * Any beforeAll must use global.maxTimeout + * Tips for usage: + * * Do not restart this global agent + * * Ensure client-side side-effects are removed at the end of each test + * * Ensure server-side side-effects are removed at the end of each test */ async function pkAgent( args: Array = [], @@ -363,6 +382,7 @@ async function pkAgent( path.join(global.binAgentDir, 'references', reference), ); lock.unlock(testLockFile.fd); + await testLockFile.close(); // If the pids directory is not empty, there are other processes still running try { await fs.promises.rmdir(path.join(global.binAgentDir, 'references')); @@ -385,6 +405,7 @@ async function pkAgent( global.binAgentDir, ); // `pk agent stop` is asynchronous, need to wait for it to be DEAD + // This also means STDERR from the stopping agent may appear on the test logs await status.waitFor('DEAD'); }; } diff --git a/tests/bin/vaults.test.ts b/tests/bin/vaults.test.ts index eed8ca1ca..1d8873a80 100644 --- a/tests/bin/vaults.test.ts +++ b/tests/bin/vaults.test.ts @@ -528,8 +528,6 @@ describe('CLI vaults', () => { const result = await utils.pkStdio([...command], {}, dataDir); expect(result.exitCode).toBe(0); - expect(result.stdout).toContain(vaultName); - expect(result.stdout).toContain(ver1Oid); const fileContents = await vault.access(async (efs) => { return (await efs.readFile(secret1.name)).toString(); @@ -562,8 +560,6 @@ describe('CLI vaults', () => { const result2 = await utils.pkStdio([...command2], {}, dataDir); expect(result2.exitCode).toBe(0); - expect(result2.stdout).toContain(vaultName); - expect(result2.stdout).toContain('latest'); }); test('should handle invalid version IDs', async () => { await polykeyAgent.vaultManager.createVault(vaultName); diff --git a/tests/client/GRPCClientClient.test.ts b/tests/client/GRPCClientClient.test.ts index 76c7b3c06..f32216641 100644 --- a/tests/client/GRPCClientClient.test.ts +++ b/tests/client/GRPCClientClient.test.ts @@ -5,16 +5,16 @@ import os from 'os'; import path from 'path'; import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; - import { GRPCClientClient } from '@/client'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; import { PolykeyAgent } from '@'; +import { Status } from '@/status'; import * as binProcessors from '@/bin/utils/processors'; import { Session } from '@/sessions'; +import config from '@/config'; import { errors as clientErrors } from '@/client'; import * as testUtils from './utils'; -// Mocks. jest.mock('@/keys/utils', () => ({ ...jest.requireActual('@/keys/utils'), generateDeterministicKeyPair: @@ -29,14 +29,12 @@ describe('GRPCClientClient', () => { let client: GRPCClientClient; let server: grpc.Server; let port: number; - let polykeyAgent: PolykeyAgent; let dataDir: string; let nodePath: string; - let nodeId: NodeId; - - beforeEach(async () => { + let session: Session; + beforeAll(async () => { dataDir = await fs.promises.mkdtemp( path.join(os.tmpdir(), 'polykey-test-'), ); @@ -46,7 +44,6 @@ describe('GRPCClientClient', () => { nodePath, logger: logger, }); - nodeId = polykeyAgent.nodeManager.getNodeId(); [server, port] = await testUtils.openTestClientServer({ polykeyAgent, @@ -57,44 +54,70 @@ describe('GRPCClientClient', () => { await session.start({ sessionToken, }); - client = await GRPCClientClient.createGRPCClientClient({ - nodeId: nodeId, - host: '127.0.0.1' as Host, - port: port as Port, - tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, - logger: logger, - timeout: 10000, - session: session, - }); - }, global.polykeyStartupTimeout * 3); - afterEach(async () => { + }, global.polykeyStartupTimeout); + afterAll(async () => { await client.destroy(); await testUtils.closeTestClientServer(server); - await polykeyAgent.stop(); await polykeyAgent.destroy(); - await fs.promises.rm(dataDir, { force: true, recursive: true, }); }); - test('cannot be called when destroyed', async () => { + client = await GRPCClientClient.createGRPCClientClient({ + nodeId: nodeId, + host: '127.0.0.1' as Host, + port: port as Port, + tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, + logger: logger, + timeout: 10000, + session: session, + }); await client.destroy(); await expect(async () => { await client.agentStatus(new utilsPB.EmptyMessage()); }).rejects.toThrow(clientErrors.ErrorClientClientDestroyed); }); test('can get status', async () => { + client = await GRPCClientClient.createGRPCClientClient({ + nodeId: nodeId, + host: '127.0.0.1' as Host, + port: port as Port, + tlsConfig: { keyPrivatePem: undefined, certChainPem: undefined }, + logger: logger, + timeout: 10000, + session: session, + }); await fs.promises.writeFile(path.join(dataDir, 'password'), password); const meta = await binProcessors.processAuthentication( path.join(dataDir, 'password'), fs, ); + const status = new Status({ + statusPath: path.join(nodePath, config.defaults.statusBase), + fs, + logger, + }); + const statusInfo = (await status.readStatus())!; const emptyMessage = new utilsPB.EmptyMessage(); const response = await client.agentStatus(emptyMessage, meta); - expect(response.getAddress()).toBeTruthy(); + expect(typeof response.getPid()).toBe('number'); + expect(response.getNodeId()).toBe(statusInfo.data.nodeId); + expect(response.getClientHost()).toBe(statusInfo.data.clientHost); + expect(response.getClientPort()).toBe(statusInfo.data.clientPort); + expect(response.getIngressHost()).toBe(statusInfo.data.ingressHost); + expect(response.getIngressPort()).toBe(statusInfo.data.ingressPort); + expect(typeof response.getEgressHost()).toBe('string'); + expect(typeof response.getEgressPort()).toBe('number'); + expect(typeof response.getAgentHost()).toBe('string'); + expect(typeof response.getAgentPort()).toBe('number'); + expect(typeof response.getProxyHost()).toBe('string'); + expect(typeof response.getProxyPort()).toBe('number'); + expect(typeof response.getRootPublicKeyPem()).toBe('string'); + expect(typeof response.getRootCertPem()).toBe('string'); + expect(typeof response.getRootCertChainPem()).toBe('string'); await client.destroy(); }); }); diff --git a/tests/client/PolykeyClient.test.ts b/tests/client/PolykeyClient.test.ts deleted file mode 100644 index 1381bbe36..000000000 --- a/tests/client/PolykeyClient.test.ts +++ /dev/null @@ -1,150 +0,0 @@ -import type * as grpc from '@grpc/grpc-js'; -import type { GRPCClientClient } from '@/client'; -import os from 'os'; -import path from 'path'; -import fs from 'fs'; -import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; -import * as binProcessors from '@/bin/utils/processors'; - -import { PolykeyClient } from '@'; -import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; -import { PolykeyAgent } from '@'; - -import * as testUtils from './utils'; - -// Mocks. -jest.mock('@/keys/utils', () => ({ - ...jest.requireActual('@/keys/utils'), - generateDeterministicKeyPair: - jest.requireActual('@/keys/utils').generateKeyPair, -})); - -describe('PolykeyClient', () => { - const password = 'password'; - const logger = new Logger('GRPCClientClientTest', LogLevel.WARN, [ - new StreamHandler(), - ]); - let client: GRPCClientClient; - let pkClient: PolykeyClient; - let server: grpc.Server; - let _port: number; - let passwordFile: string; - let meta: grpc.Metadata; - - let dataDir: string; - let nodePath: string; - let clientPath: string; - - let polykeyAgent: PolykeyAgent; - - beforeEach(async () => { - dataDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'polykey-test-'), - ); - nodePath = path.join(dataDir, 'node'); - clientPath = path.join(dataDir, 'client'); - passwordFile = path.join(dataDir, 'password'); - await fs.promises.writeFile(passwordFile, password); - meta = await binProcessors.processAuthentication(passwordFile, fs); - - polykeyAgent = await PolykeyAgent.createPolykeyAgent({ - password, - nodePath, - logger: logger, - }); - - [server, _port] = await testUtils.openTestClientServer({ - polykeyAgent, - secure: false, - }); - - pkClient = await PolykeyClient.createPolykeyClient({ - nodeId: polykeyAgent.keyManager.getNodeId(), - host: polykeyAgent.grpcServerClient.host, - port: polykeyAgent.grpcServerClient.port, - nodePath: clientPath, - fs: fs, - logger: logger, - }); - client = pkClient.grpcClient; - - const sessionToken = await polykeyAgent.sessionManager.createToken(); - await pkClient.session.start({ sessionToken }); - }); - afterEach(async () => { - await client.destroy(); - await pkClient.stop(); - await testUtils.closeTestClientServer(server); - - await polykeyAgent.stop(); - await polykeyAgent.destroy(); - - await fs.promises.rm(dataDir, { - force: true, - recursive: true, - }); - }); - test('can get status', async () => { - const emptyMessage = new utilsPB.EmptyMessage(); - const response = await client.agentStatus(emptyMessage, meta); - expect(response.getNodeId()).toBeTruthy(); - expect(response.getAddress()).toBeTruthy(); - expect(response.getCert()).toBeTruthy(); - }); - describe('TLS tests', () => { - const password = 'password'; - const logger = new Logger('PolykeyAgent TLS', LogLevel.WARN, [ - new StreamHandler(), - ]); - let dataDir: string; - let nodePath2: string; - let clientPath2: string; - let polykeyAgent2: PolykeyAgent; - let sessionToken; - - beforeAll(async () => { - // Setting up paths and dirs. - dataDir = await fs.promises.mkdtemp( - path.join(os.tmpdir(), 'polykey-test-'), - ); - nodePath2 = path.join(dataDir, 'keynode'); - clientPath2 = path.join(dataDir, 'client2'); - - // Starting an agent. - polykeyAgent2 = await PolykeyAgent.createPolykeyAgent({ - password, - nodePath: nodePath2, - logger: logger.getChild(PolykeyAgent.name), - }); - - sessionToken = await polykeyAgent2.sessionManager.createToken(); - }, global.defaultTimeout * 3); - afterAll(async () => { - await polykeyAgent2.stop(); - await polykeyAgent2.destroy(); - }); - test('can get status over TLS', async () => { - // Starting client. - const pkClient = await PolykeyClient.createPolykeyClient({ - nodeId: polykeyAgent2.keyManager.getNodeId(), - host: polykeyAgent2.grpcServerClient.host, - port: polykeyAgent2.grpcServerClient.port, - nodePath: clientPath2, - fs: fs, - logger: logger.getChild(PolykeyClient.name), - }); - await pkClient.session.start({ sessionToken }); - const meta = await binProcessors.processAuthentication(passwordFile, fs); - - const emptyMessage = new utilsPB.EmptyMessage(); - const response = await pkClient.grpcClient.agentStatus( - emptyMessage, - meta, - ); - expect(response.getNodeId()).toBeTruthy(); - expect(response.getAddress()).toBeTruthy(); - expect(response.getCert()).toBeTruthy(); - expect(pkClient.grpcClient.secured).toBeTruthy(); - }); - }); -}); diff --git a/tests/client/rpcSessions.test.ts b/tests/client/rpcSessions.test.ts index 96a149a3a..581e93725 100644 --- a/tests/client/rpcSessions.test.ts +++ b/tests/client/rpcSessions.test.ts @@ -1,5 +1,4 @@ import type * as grpc from '@grpc/grpc-js'; -import type { SessionToken } from '@/sessions/types'; import type { ClientServiceClient } from '@/proto/js/polykey/v1/client_service_grpc_pb'; import os from 'os'; import path from 'path'; @@ -7,12 +6,10 @@ import fs from 'fs'; import Logger, { LogLevel, StreamHandler } from '@matrixai/logger'; import { PolykeyAgent } from '@'; import * as utilsPB from '@/proto/js/polykey/v1/utils/utils_pb'; -import * as sessionsPB from '@/proto/js/polykey/v1/sessions/sessions_pb'; import { KeyManager } from '@/keys'; import { ForwardProxy } from '@/network'; import * as grpcUtils from '@/grpc/utils'; -import { sleep } from '@/utils'; -import * as errors from '@/errors'; +import * as clientUtils from '@/client/utils'; import * as testUtils from './utils'; // Mocks. @@ -22,19 +19,6 @@ jest.mock('@/keys/utils', () => ({ jest.requireActual('@/keys/utils').generateKeyPair, })); -/** - * This test file has been optimised to use only one instance of PolykeyAgent where posible. - * Setting up the PolykeyAgent has been done in a beforeAll block. - * Keep this in mind when adding or editing tests. - * Any side effects need to be undone when the test has completed. - * Preferably within a `afterEach()` since any cleanup will be skipped inside a failing test. - * - * - left over state can cause a test to fail in certain cases. - * - left over state can cause similar tests to succeed when they should fail. - * - starting or stopping the agent within tests should be done on a new instance of the polykey agent. - * - when in doubt test each modified or added test on it's own as well as the whole file. - * - Looking into adding a way to safely clear each domain's DB information with out breaking modules. - */ describe('Sessions client service', () => { const password = 'password'; const logger = new Logger('SessionsClientServerTest', LogLevel.WARN, [ @@ -101,81 +85,27 @@ describe('Sessions client service', () => { const sessionToken = await polykeyAgent.sessionManager.createToken(); callCredentials = testUtils.createCallCredentials(sessionToken); }); - test('can request a session', async () => { - const requestJWT = grpcUtils.promisifyUnaryCall( + const unlock = grpcUtils.promisifyUnaryCall( client, client.sessionsUnlock, ); - const passwordMessage = new sessionsPB.Password(); - passwordMessage.setPassword(passwordFile); - - const res = await requestJWT(passwordMessage); - expect(typeof res.getToken()).toBe('string'); - const result = await polykeyAgent.sessionManager.verifyToken( - res.getToken() as SessionToken, - ); + const pCall = unlock(new utilsPB.EmptyMessage(), callCredentials); + const meta = await pCall.meta; + const token = clientUtils.decodeAuthToSession(meta); + const result = await polykeyAgent.sessionManager.verifyToken(token!); expect(result).toBeTruthy(); }); - test('can refresh session', async () => { - const requestJWT = grpcUtils.promisifyUnaryCall( - client, - client.sessionsUnlock, - ); - - const passwordMessage = new sessionsPB.Password(); - passwordMessage.setPassword(passwordFile); - - const res1 = await requestJWT(passwordMessage); - const token1 = res1.getToken() as SessionToken; - const callCredentialsRefresh = testUtils.createCallCredentials(token1); - - const sessionRefresh = grpcUtils.promisifyUnaryCall( - client, - client.sessionsRefresh, - ); - - await sleep(1100); - const emptyMessage = new utilsPB.EmptyMessage(); - const res2 = await sessionRefresh(emptyMessage, callCredentialsRefresh); - expect(typeof res2.getToken()).toBe('string'); - const token2 = res2.getToken() as SessionToken; - const result = await polykeyAgent.sessionManager.verifyToken(token2); - expect(result).toBeTruthy(); - expect(token1).not.toEqual(token2); - }); - test('actions over GRPC refresh the session', async () => { - // Since we refresh the token when metadata is sent, check that - // metadata is sent and that we can do something when it happens - const agentStatus = grpcUtils.promisifyUnaryCall( - client, - client.agentStatus, - ); - const emptyMessage = new utilsPB.EmptyMessage(); - const res = agentStatus(emptyMessage, callCredentials); - let check = 0; - res.call.on('metadata', () => (check = 1)); - await res; - expect(check).toEqual(1); - }); - test('session can lock all', async () => { - const agentStatus = grpcUtils.promisifyUnaryCall( - client, - client.agentStatus, - ); - - // Locking the session. - const sessionLockAll = grpcUtils.promisifyUnaryCall( + test('can lock all sessions', async () => { + const lockall = grpcUtils.promisifyUnaryCall( client, client.sessionsLockAll, ); - const emptyMessage = new utilsPB.EmptyMessage(); - await sessionLockAll(emptyMessage, callCredentials); - // Should reject the session token. - await expect(() => agentStatus(emptyMessage)).rejects.toThrow( - errors.ErrorClientAuthMissing, - ); + await lockall(new utilsPB.EmptyMessage(), callCredentials); + const prevToken = clientUtils.decodeAuthToSession(callCredentials); + const result = await polykeyAgent.sessionManager.verifyToken(prevToken!); + expect(result).toBeFalsy(); }); }); diff --git a/tests/client/utils.ts b/tests/client/utils.ts index 6aa9f0c43..6ca47d3af 100644 --- a/tests/client/utils.ts +++ b/tests/client/utils.ts @@ -35,7 +35,8 @@ async function openTestClientServer({ discovery: polykeyAgent.discovery, fwdProxy: polykeyAgent.fwdProxy, revProxy: polykeyAgent.revProxy, - clientGrpcServer: polykeyAgent.grpcServerClient, + grpcServerClient: polykeyAgent.grpcServerClient, + grpcServerAgent: polykeyAgent.grpcServerAgent, fs: polykeyAgent.fs, }); diff --git a/tests/globalSetup.ts b/tests/globalSetup.ts index c97a0baf5..8a976ac68 100644 --- a/tests/globalSetup.ts +++ b/tests/globalSetup.ts @@ -1,13 +1,41 @@ +/** + * Global setup for all jest tests + * Side-effects are performed here + * No variable context is passed to the test modules + * Jest does not support `@/` imports here + * @module + */ import os from 'os'; import fs from 'fs'; import path from 'path'; +import * as keysUtils from '../src/keys/utils'; async function setup() { // eslint-disable-next-line no-console console.log('\nGLOBAL SETUP'); - // Globals defined in setup.ts is not available here + // Globals defined in setup.ts must be copied here + const keyPairDir = path.join(os.tmpdir(), 'polykey-test-keypair'); const binAgentDir = path.join(os.tmpdir(), 'polykey-test-bin'); - // The global agent directory must be fresh + // Setup global root key pair + // eslint-disable-next-line no-console + console.log(`Creating global.keyPairDir: ${keyPairDir}`); + await fs.promises.rm(keyPairDir, { force: true, recursive: true }); + await fs.promises.mkdir(keyPairDir); + const rootKeyPair = await keysUtils.generateKeyPair(1024); + const rootKeyPairPem = keysUtils.keyPairToPem(rootKeyPair); + await Promise.all([ + fs.promises.writeFile( + path.join(keyPairDir, 'root.pub'), + rootKeyPairPem.publicKey, + 'utf-8', + ), + fs.promises.writeFile( + path.join(keyPairDir, 'root.key'), + rootKeyPairPem.privateKey, + 'utf-8', + ), + ]); + // Setup global agent directory // eslint-disable-next-line no-console console.log(`Creating global.binAgentDir: ${binAgentDir}`); await fs.promises.rm(binAgentDir, { force: true, recursive: true }); diff --git a/tests/globalTeardown.ts b/tests/globalTeardown.ts index 0f2df08a5..0959608ad 100644 --- a/tests/globalTeardown.ts +++ b/tests/globalTeardown.ts @@ -1,3 +1,10 @@ +/** + * Global teardown for all jest tests + * Side-effects are performed here + * No variable context is inherited from test modules + * Jest does not support `@/` imports here + * @module + */ import os from 'os'; import fs from 'fs'; import path from 'path'; @@ -5,8 +12,12 @@ import path from 'path'; async function teardown() { // eslint-disable-next-line no-console console.log('GLOBAL TEARDOWN'); - // Globals defined in setup.ts is not available here + // Globals defined in setup.ts must be copied here + const keyPairDir = path.join(os.tmpdir(), 'polykey-test-keypair'); const binAgentDir = path.join(os.tmpdir(), 'polykey-test-bin'); + // eslint-disable-next-line no-console + console.log(`Destroying global.keyPairDir: ${keyPairDir}`); + await fs.promises.rm(keyPairDir, { force: true, recursive: true }); // The global agent directory must be fresh // eslint-disable-next-line no-console console.log(`Destroying global.binAgentDir: ${binAgentDir}`); diff --git a/tests/grpc/utils/testService.ts b/tests/grpc/utils/testService.ts index 20e2002f1..b6ee75236 100644 --- a/tests/grpc/utils/testService.ts +++ b/tests/grpc/utils/testService.ts @@ -75,7 +75,7 @@ function createTestService({ new grpcErrors.ErrorGRPC('test error', { grpc: true }), ); } else { - // Will send back a number of messsage + // Will send back a number of message // equal to the character length of the challenge string for (let i = 0; i < messageFrom.getChallenge().length; i++) { messageTo.setChallenge(messageFrom.getChallenge()); diff --git a/tests/setup.ts b/tests/setup.ts index d79c793fb..5cac9b6aa 100644 --- a/tests/setup.ts +++ b/tests/setup.ts @@ -6,6 +6,7 @@ declare global { interface Global { projectDir: string; testDir: string; + keyPairDir: string; binAgentDir: string; binAgentPassword: string; defaultTimeout: number; @@ -26,6 +27,13 @@ global.projectDir = path.join(__dirname, '../'); */ global.testDir = __dirname; +/** + * Absolute directory to shared keypair directory + * Generating the root key pair takes time + * This global key pair can be used by mocks + */ +global.keyPairDir = path.join(os.tmpdir(), 'polykey-test-keypair'); + /** * Absolute directory to a shared data directory used by bin tests * This has to be a static path diff --git a/tests/utils.ts b/tests/utils.ts index debd93584..a3bd2027f 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -3,8 +3,19 @@ import type { NodeAddress } from '@/nodes/types'; import os from 'os'; import path from 'path'; import fs from 'fs'; -import { utils as keyUtils } from '@/keys'; -import { PolykeyAgent } from '../src'; +import { PolykeyAgent } from '@'; +import * as keysUtils from '@/keys/utils'; + +async function getGlobalKeyPair() { + const [publicKeyPem, privateKeyPem] = await Promise.all([ + fs.promises.readFile(path.join(global.keyPairDir, 'root.pub'), 'utf-8'), + fs.promises.readFile(path.join(global.keyPairDir, 'root.key'), 'utf-8'), + ]); + return keysUtils.keyPairFromPem({ + publicKey: publicKeyPem, + privateKey: privateKeyPem, + }); +} /** * Helper function to create a remote keynode to contact. @@ -65,13 +76,14 @@ function makeCrypto(dbKey: Buffer) { return { key: dbKey, ops: { - encrypt: keyUtils.encryptWithKey, - decrypt: keyUtils.decryptWithKey, + encrypt: keysUtils.encryptWithKey, + decrypt: keysUtils.decryptWithKey, }, }; } export { + getGlobalKeyPair, setupRemoteKeynode, cleanupRemoteKeynode, addRemoteDetails,