Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Wrapping VaultOps errors in ErrorPolykey errors and updating tests #838

Merged
merged 1 commit into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"@matrixai/mdns": "^1.2.6",
"@matrixai/quic": "^1.2.10",
"@matrixai/resources": "^1.1.5",
"@matrixai/rpc": "^0.5.1",
"@matrixai/rpc": "^0.6.0",
"@matrixai/timer": "^1.1.3",
"@matrixai/workers": "^1.3.7",
"@matrixai/ws": "^1.1.7",
Expand Down
3 changes: 3 additions & 0 deletions src/client/callers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import vaultsPermissionUnset from './vaultsPermissionUnset';
import vaultsPull from './vaultsPull';
import vaultsRename from './vaultsRename';
import vaultsScan from './vaultsScan';
import vaultsSecretsCat from './vaultsSecretsCat';
import vaultsSecretsEnv from './vaultsSecretsEnv';
import vaultsSecretsGet from './vaultsSecretsGet';
import vaultsSecretsList from './vaultsSecretsList';
Expand Down Expand Up @@ -144,6 +145,7 @@ const clientManifest = {
vaultsPull,
vaultsRename,
vaultsScan,
vaultsSecretsCat,
vaultsSecretsEnv,
vaultsSecretsGet,
vaultsSecretsList,
Expand Down Expand Up @@ -224,6 +226,7 @@ export {
vaultsPull,
vaultsRename,
vaultsScan,
vaultsSecretsCat,
vaultsSecretsEnv,
vaultsSecretsGet,
vaultsSecretsList,
Expand Down
12 changes: 12 additions & 0 deletions src/client/callers/vaultsSecretsCat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { HandlerTypes } from '@matrixai/rpc';
import type VaultsSecretsCat from '../handlers/VaultsSecretsCat';
import { DuplexCaller } from '@matrixai/rpc';

type CallerTypes = HandlerTypes<VaultsSecretsCat>;

const vaultsSecretsCat = new DuplexCaller<
CallerTypes['input'],
CallerTypes['output']
>();

export default vaultsSecretsCat;
4 changes: 2 additions & 2 deletions src/client/callers/vaultsSecretsGet.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { HandlerTypes } from '@matrixai/rpc';
import type VaultsSecretsGet from '../handlers/VaultsSecretsGet';
import { DuplexCaller } from '@matrixai/rpc';
import { ServerCaller } from '@matrixai/rpc';

type CallerTypes = HandlerTypes<VaultsSecretsGet>;

const vaultsSecretsGet = new DuplexCaller<
const vaultsSecretsGet = new ServerCaller<
CallerTypes['input'],
CallerTypes['output']
>();
Expand Down
4 changes: 2 additions & 2 deletions src/client/callers/vaultsSecretsRemove.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { HandlerTypes } from '@matrixai/rpc';
import type VaultsSecretsRemove from '../handlers/VaultsSecretsRemove';
import { ClientCaller } from '@matrixai/rpc';
import { DuplexCaller } from '@matrixai/rpc';

type CallerTypes = HandlerTypes<VaultsSecretsRemove>;

const vaultsSecretsRemove = new ClientCaller<
const vaultsSecretsRemove = new DuplexCaller<
CallerTypes['input'],
CallerTypes['output']
>();
Expand Down
71 changes: 71 additions & 0 deletions src/client/handlers/VaultsSecretsCat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type { DB } from '@matrixai/db';
import type {
ClientRPCRequestParams,
ClientRPCResponseResult,
ContentOrErrorMessage,
SecretIdentifierMessage,
} from '../types';
import type VaultManager from '../../vaults/VaultManager';
import { DuplexHandler } from '@matrixai/rpc';
import * as vaultsUtils from '../../vaults/utils';
import * as vaultsErrors from '../../vaults/errors';
import * as vaultOps from '../../vaults/VaultOps';

// This method takes in multiple secret paths, and either returns the file
// contents, or an `ErrorMessage` signifying the error. To read a single secret
// instead, refer to `VaultsSecretsGet`.
class VaultsSecretsCat extends DuplexHandler<
{
db: DB;
vaultManager: VaultManager;
},
ClientRPCRequestParams<SecretIdentifierMessage>,
ClientRPCResponseResult<ContentOrErrorMessage>
> {
public handle = async function* (
input: AsyncIterable<ClientRPCRequestParams<SecretIdentifierMessage>>,
): AsyncGenerator<ClientRPCResponseResult<ContentOrErrorMessage>> {
const { db, vaultManager }: { db: DB; vaultManager: VaultManager } =
this.container;
yield* db.withTransactionG(async function* (tran): AsyncGenerator<
ClientRPCResponseResult<ContentOrErrorMessage>
> {
// As we need to preserve the order of parameters, we need to loop over
// them individually, as grouping them would make them go out of order.
for await (const secretIdentiferMessage of input) {
const { nameOrId, secretName } = secretIdentiferMessage;
const vaultIdFromName = await vaultManager.getVaultId(nameOrId, tran);
const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(nameOrId);
if (vaultId == null) throw new vaultsErrors.ErrorVaultsVaultUndefined();
yield await vaultManager.withVaults(
[vaultId],
async (vault) => {
try {
const content = await vaultOps.getSecret(vault, secretName);
return {
type: 'success',
success: true,
secretContent: content.toString('binary'),
};
} catch (e) {
if (
e instanceof vaultsErrors.ErrorSecretsSecretUndefined ||
e instanceof vaultsErrors.ErrorSecretsIsDirectory
) {
return {
type: 'error',
code: e.cause.code,
reason: secretName,
};
}
throw e;
}
},
tran,
);
}
});
};
}

export default VaultsSecretsCat;
72 changes: 22 additions & 50 deletions src/client/handlers/VaultsSecretsGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,44 @@ import type { DB } from '@matrixai/db';
import type {
ClientRPCRequestParams,
ClientRPCResponseResult,
ContentWithErrorMessage,
ContentMessage,
SecretIdentifierMessage,
} from '../types';
import type VaultManager from '../../vaults/VaultManager';
import { DuplexHandler } from '@matrixai/rpc';
import { ServerHandler } from '@matrixai/rpc';
import * as vaultsUtils from '../../vaults/utils';
import * as vaultsErrors from '../../vaults/errors';
import * as vaultOps from '../../vaults/VaultOps';

class VaultsSecretsGet extends DuplexHandler<
// This method only returns the contents of a single secret, and throws an error
// if the secret couldn't be read. To read multiple secrets, refer to
// `VaultsSecretsCat`.
class VaultsSecretsGet extends ServerHandler<
{
db: DB;
vaultManager: VaultManager;
},
ClientRPCRequestParams<SecretIdentifierMessage>,
ClientRPCResponseResult<ContentWithErrorMessage>
ClientRPCResponseResult<ContentMessage>
> {
public handle = async function* (
input: AsyncIterable<ClientRPCRequestParams<SecretIdentifierMessage>>,
_cancel,
_meta,
ctx,
): AsyncGenerator<ClientRPCResponseResult<ContentWithErrorMessage>> {
if (ctx.signal.aborted) throw ctx.signal.reason;
input: ClientRPCRequestParams<SecretIdentifierMessage>,
): AsyncGenerator<ClientRPCResponseResult<ContentMessage>> {
const { db, vaultManager }: { db: DB; vaultManager: VaultManager } =
this.container;
yield* db.withTransactionG(async function* (tran): AsyncGenerator<
ClientRPCResponseResult<ContentWithErrorMessage>
> {
if (ctx.signal.aborted) throw ctx.signal.reason;
// As we need to preserve the order of parameters, we need to loop over
// them individually, as grouping them would make them go out of order.
let metadata: any = undefined;
for await (const secretIdentiferMessage of input) {
if (ctx.signal.aborted) throw ctx.signal.reason;
if (metadata == null) metadata = secretIdentiferMessage.metadata ?? {};
const { nameOrId, secretName } = secretIdentiferMessage;
const vaultIdFromName = await vaultManager.getVaultId(nameOrId, tran);
const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(nameOrId);
if (vaultId == null) throw new vaultsErrors.ErrorVaultsVaultUndefined();
yield await vaultManager.withVaults(
[vaultId],
async (vault) => {
try {
const content = await vaultOps.getSecret(vault, secretName);
return { secretContent: content.toString('binary') };
} catch (e) {
if (metadata?.options?.continueOnError === true) {
if (e instanceof vaultsErrors.ErrorSecretsSecretUndefined) {
return {
secretContent: '',
error: `${e.name}: ${secretName}: No such secret or directory\n`,
};
} else if (e instanceof vaultsErrors.ErrorSecretsIsDirectory) {
return {
secretContent: '',
error: `${e.name}: ${secretName}: Is a directory\n`,
};
}
}
throw e;
}
},
tran,
);
}
yield await db.withTransactionF(async (tran) => {
const vaultIdFromName = await vaultManager.getVaultId(
input.nameOrId,
tran,
);
const vaultId =
vaultIdFromName ?? vaultsUtils.decodeVaultId(input.nameOrId);
if (vaultId == null) throw new vaultsErrors.ErrorVaultsVaultUndefined();
// Get the contents of the file
return await vaultManager.withVaults([vaultId], async (vault) => {
const content = await vaultOps.getSecret(vault, input.secretName);
return { secretContent: content.toString('binary') };
});
});
};
}
Expand Down
22 changes: 19 additions & 3 deletions src/client/handlers/VaultsSecretsMkdir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,25 @@ class VaultsSecretsMkdir extends DuplexHandler<
yield await vaultManager.withVaults(
[vaultId],
async (vault) => {
return await vaultOps.mkdir(vault, dirName, {
recursive: metadata?.options?.recursive,
});
try {
await vaultOps.mkdir(vault, dirName, {
recursive: metadata?.options?.recursive,
});
return { type: 'success', success: true };
} catch (e) {
if (
e instanceof vaultsErrors.ErrorVaultsRecursive ||
e instanceof vaultsErrors.ErrorSecretsSecretDefined
) {
return {
type: 'error',
code: e.cause.code,
reason: dirName,
};
} else {
throw e;
}
}
},
tran,
);
Expand Down
Loading