Skip to content

Commit

Permalink
feat: error serialisation/deserialisation over gRPC incorporating err…
Browse files Browse the repository at this point in the history
…or chaining

Our gRPC `toError` and `fromError` utils are now able to serialise and deserialise Polykey and non-Polykey errors (as well as non-errors), including the entire error chain if this exists. Also includes the ability to filter out sensitive data, for example when the error is being sent to another agent.

Errors sent over the network in this way are now additionally wrapped on the receiving side in an `ErrorPolykeyRemote` to make the source of the error more clear.

#304
  • Loading branch information
emmacasolin committed Jun 6, 2022
1 parent 343b7dc commit 477d111
Show file tree
Hide file tree
Showing 24 changed files with 353 additions and 62 deletions.
63 changes: 52 additions & 11 deletions src/ErrorPolykey.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,61 @@
import type { POJO } from './types';
import { AbstractError } from '@matrixai/errors';
import sysexits from './utils/sysexits';

class ErrorPolykey<T> extends AbstractError<T> {
static description: string = 'Polykey error';
exitCode: number = sysexits.GENERAL;
toJSON(): string {
return JSON.stringify({
name: this.name,
description: this.description,
message: this.message,
exitCode: this.exitCode,
timestamp: this.timestamp,
data: this.data,
cause: this.cause,
stack: this.stack,
});
public toJSON(
_key: string = '',
options: {
description?: boolean;
message?: boolean,
exitCode?: boolean,
timestamp?: boolean;
data?: boolean;
cause?: boolean;
stack?: boolean;
} = {}
): {
type: string;
data: {
description?: string;
message?: string;
exitCode?: number,
timestamp?: Date,
data?: POJO;
cause?: T,
stack?: string
}
} {
options.description ??= true;
options.message ??= true;
options.exitCode ??= true;
options.timestamp ??= true;
options.data ??= true;
options.cause ??= true;
options.stack ??= true;
const data: POJO = {};
if (options.description) data.description = this.description;
if (options.message) data.message = this.message;
if (options.exitCode) data.exitCode = this.exitCode;
if (options.timestamp) data.timestamp = this.timestamp;
if (options.data) data.data = this.data;
if (options.cause) {
// Propagate the options down the exception chain
// but only if the cause is another AbstractError
if (this.cause instanceof ErrorPolykey) {
data.cause = this.cause.toJSON('cause', options);
} else {
// Use `replacer` to further encode this object
data.cause = this.cause;
}
}
if (options.stack) data.stack = this.stack;
return {
type: this.name,
data
};
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/nodesChainDataGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function nodesChainDataGet({ sigchain }: { sigchain: Sigchain }) {
callback(null, response);
return;
} catch (e) {
callback(grpcUtils.fromError(e));
callback(grpcUtils.fromError(e, true));
return;
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/nodesClosestLocalNodesGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function nodesClosestLocalNodesGet({
callback(null, response);
return;
} catch (e) {
callback(grpcUtils.fromError(e));
callback(grpcUtils.fromError(e, true));
return;
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/nodesCrossSignClaim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function nodesCrossSignClaim({
) => {
// TODO: Move all "await genClaims.throw" to a final catch(). Wrap this
// entire thing in a try block. And re-throw whatever error is caught
const genClaims = grpcUtils.generatorDuplex(call);
const genClaims = grpcUtils.generatorDuplex(call, true);
try {
await sigchain.transaction(async (sigchain) => {
const readStatus = await genClaims.read();
Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/nodesHolePunchMessageSend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function nodesHolePunchMessageSend({
callback(null, response);
return;
} catch (e) {
callback(grpcUtils.fromError(e));
callback(grpcUtils.fromError(e, true));
return;
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/notificationsSend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function notificationsSend({
callback(null, response);
return;
} catch (e) {
callback(grpcUtils.fromError(e));
callback(grpcUtils.fromError(e, true));
return;
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/vaultsGitInfoGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function vaultsGitInfoGet({
return async (
call: grpc.ServerWritableStream<vaultsPB.InfoRequest, vaultsPB.PackChunk>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, true);
const request = call.request;
const vaultMessage = request.getVault();
if (vaultMessage == null) {
Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/vaultsGitPackGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function vaultsGitPackGet({
return async (
call: grpc.ServerDuplexStream<vaultsPB.PackChunk, vaultsPB.PackChunk>,
) => {
const genDuplex = grpcUtils.generatorDuplex(call);
const genDuplex = grpcUtils.generatorDuplex(call, true);
const clientBodyBuffers: Uint8Array[] = [];
const clientRequest = (await genDuplex.read()).value;
clientBodyBuffers.push(clientRequest!.getChunk_asU8());
Expand Down
2 changes: 1 addition & 1 deletion src/agent/service/vaultsScan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function vaultsScan({
return async (
call: grpc.ServerWritableStream<utilsPB.EmptyMessage, vaultsPB.List>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, true);
const listMessage = new vaultsPB.List();
// Getting the NodeId from the ReverseProxy connection info
const connectionInfo = connectionInfoGet(call);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/gestaltsGestaltList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function gestaltsGestaltList({
return async (
call: grpc.ServerWritableStream<utilsPB.EmptyMessage, gestaltsPB.Gestalt>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
let gestaltMessage: gestaltsPB.Gestalt;
try {
const metadata = await authenticate(call.metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/identitiesAuthenticate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function identitiesAuthenticate({
identitiesPB.AuthenticationProcess
>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/identitiesAuthenticatedGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function identitiesAuthenticatedGet({
identitiesPB.Provider
>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/identitiesInfoConnectedGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function identitiesInfoConnectedGet({
identitiesPB.Info
>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/identitiesInfoGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function identitiesInfoGet({
identitiesPB.Info
>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/keysCertsChainGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function keysCertsChainGet({
return async (
call: grpc.ServerWritableStream<utilsPB.EmptyMessage, keysPB.Certificate>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/vaultsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function vaultsList({
// Call.on('error', (e) => console.error(e));
// call.on('close', () => console.log('Got close'));
// call.on('finish', () => console.log('Got finish'));
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/vaultsLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function vaultsLog({
return async (
call: grpc.ServerWritableStream<vaultsPB.Log, vaultsPB.LogEntry>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/vaultsPermissionGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function vaultsPermissionGet({
return async (
call: grpc.ServerWritableStream<vaultsPB.Vault, vaultsPB.Permissions>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const vaultMessage = call.request;
const metadata = await authenticate(call.metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/vaultsScan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function vaultsScan({
return async (
call: grpc.ServerWritableStream<nodesPB.Node, vaultsPB.List>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
2 changes: 1 addition & 1 deletion src/client/service/vaultsSecretsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function vaultsSecretsList({
return async (
call: grpc.ServerWritableStream<vaultsPB.Vault, secretsPB.Secret>,
): Promise<void> => {
const genWritable = grpcUtils.generatorWritable(call);
const genWritable = grpcUtils.generatorWritable(call, false);
try {
const metadata = await authenticate(call.metadata);
call.sendMetadata(metadata);
Expand Down
12 changes: 12 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ class ErrorPolykeyUnimplemented<T> extends ErrorPolykey<T> {
exitCode = sysexits.UNAVAILABLE;
}

class ErrorPolykeyUnknown<T> extends ErrorPolykey<T> {
static description = 'Unable to deserialise to known error';
exitCode = sysexits.UNKNOWN;
}

class ErrorPolykeyRemote<T> extends ErrorPolykey<T> {
static description = 'Remote error from RPC call';
exitCode = sysexits.UNAVAILABLE;
}

class ErrorPolykeyAgentRunning<T> extends ErrorPolykey<T> {
static description = 'PolykeyAgent is running';
exitCode = sysexits.USAGE;
Expand Down Expand Up @@ -44,6 +54,8 @@ export {
sysexits,
ErrorPolykey,
ErrorPolykeyUnimplemented,
ErrorPolykeyUnknown,
ErrorPolykeyRemote,
ErrorPolykeyAgentRunning,
ErrorPolykeyAgentNotRunning,
ErrorPolykeyAgentDestroyed,
Expand Down
Loading

0 comments on commit 477d111

Please sign in to comment.