Skip to content

Commit

Permalink
feat: updated all handlers for Vaults and VaultsSecrets with ctx
Browse files Browse the repository at this point in the history
  • Loading branch information
aryanjassal committed Jan 7, 2025
1 parent 6f131d4 commit 96acf2a
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 93 deletions.
12 changes: 9 additions & 3 deletions src/client/handlers/VaultsSecretsCat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { ContextTimed } from '@matrixai/contexts';
import type { DB } from '@matrixai/db';
import type { JSONValue } from '@matrixai/rpc';
import type {
ClientRPCRequestParams,
ClientRPCResponseResult,
Expand Down Expand Up @@ -26,16 +28,20 @@ class VaultsSecretsCat extends DuplexHandler<
input: AsyncIterableIterator<
ClientRPCRequestParams<SecretIdentifierMessage>
>,
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue>,
ctx: ContextTimed,
): 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;
// them individually. Grouping them would make them go out of order.
for await (const secretIdentifierMessage of input) {
ctx.signal.throwIfAborted();
const { nameOrId, secretName } = secretIdentifierMessage;
const vaultIdFromName = await vaultManager.getVaultId(nameOrId, tran);
const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(nameOrId);
if (vaultId == null) throw new vaultsErrors.ErrorVaultsVaultUndefined();
Expand Down
12 changes: 7 additions & 5 deletions src/client/handlers/VaultsSecretsEnv.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { ContextTimed } from '@matrixai/contexts';
import type { DB } from '@matrixai/db';
import type { JSONValue } from '@matrixai/rpc';
import type {
ClientRPCRequestParams,
ClientRPCResponseResult,
Expand All @@ -22,19 +24,18 @@ class VaultsSecretsEnv extends DuplexHandler<
input: AsyncIterableIterator<
ClientRPCRequestParams<SecretIdentifierMessage>
>,
_cancel,
_meta,
ctx,
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue>,
ctx: ContextTimed,
): AsyncGenerator<ClientRPCResponseResult<SecretContentMessage>> {
if (ctx.signal.aborted) throw ctx.signal.reason;
const { db, vaultManager }: { db: DB; vaultManager: VaultManager } =
this.container;

return yield* db.withTransactionG(async function* (tran): AsyncGenerator<
ClientRPCResponseResult<SecretContentMessage>
> {
if (ctx.signal.aborted) throw ctx.signal.reason;
for await (const secretIdentifierMessage of input) {
ctx.signal.throwIfAborted();
const { nameOrId, secretName } = secretIdentifierMessage;
const vaultIdFromName = await vaultManager.getVaultId(nameOrId, tran);
const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(nameOrId);
Expand Down Expand Up @@ -75,6 +76,7 @@ class VaultsSecretsEnv extends DuplexHandler<
tran,
);
for (const { filePath, value } of secrets) {
ctx.signal.throwIfAborted();
yield {
nameOrId: nameOrId,
secretName: filePath,
Expand Down
58 changes: 31 additions & 27 deletions src/client/handlers/VaultsSecretsList.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { ContextTimed } from '@matrixai/contexts';
import type { DB } from '@matrixai/db';
import type { JSONValue } from '@matrixai/rpc';
import type {
ClientRPCRequestParams,
ClientRPCResponseResult,
Expand All @@ -21,7 +23,10 @@ class VaultsSecretsList extends ServerHandler<
> {
public handle = async function* (
input: ClientRPCRequestParams<SecretIdentifierMessage>,
): AsyncGenerator<ClientRPCResponseResult<SecretFilesMessage>, void, void> {
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue>,
ctx: ContextTimed,
): AsyncGenerator<ClientRPCResponseResult<SecretFilesMessage>> {
const { db, vaultManager }: { db: DB; vaultManager: VaultManager } =
this.container;
const vaultId = await db.withTransactionF(async (tran) => {
Expand All @@ -36,34 +41,33 @@ class VaultsSecretsList extends ServerHandler<
});

yield* vaultManager.withVaultsG([vaultId], (vault) => {
return vault.readG(async function* (fs): AsyncGenerator<
SecretFilesMessage,
void,
void
> {
let files: Array<string | Buffer>;
try {
files = await fs.promises.readdir(input.secretName);
} catch (e) {
if (e.code === 'ENOENT') {
throw new vaultsErrors.ErrorSecretsDirectoryUndefined(e.message, {
cause: e,
});
return vault.readG(
async function* (fs): AsyncGenerator<SecretFilesMessage> {
let files: Array<string | Buffer>;
try {
files = await fs.promises.readdir(input.secretName);
} catch (e) {
if (e.code === 'ENOENT') {
throw new vaultsErrors.ErrorSecretsDirectoryUndefined(e.message, {
cause: e,
});
}
if (e.code === 'ENOTDIR') {
throw new vaultsErrors.ErrorSecretsIsSecret(e.message, {
cause: e,
});
}
throw e;
}
if (e.code === 'ENOTDIR') {
throw new vaultsErrors.ErrorSecretsIsSecret(e.message, {
cause: e,
});
for await (const file of files) {
ctx.signal.throwIfAborted();
const filePath = path.join(input.secretName, file.toString());
const stat = await fs.promises.stat(filePath);
const type = stat.isFile() ? 'FILE' : 'DIRECTORY';
yield { path: filePath, type: type };
}
throw e;
}
for await (const file of files) {
const filePath = path.join(input.secretName, file.toString());
const stat = await fs.promises.stat(filePath);
const type = stat.isFile() ? 'FILE' : 'DIRECTORY';
yield { path: filePath, type: type };
}
});
},
);
});
};
}
Expand Down
11 changes: 7 additions & 4 deletions src/client/handlers/VaultsSecretsMkdir.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { ContextTimed } from '@matrixai/contexts';
import type { DB } from '@matrixai/db';
import type { JSONValue } from '@matrixai/rpc';
import type {
ClientRPCRequestParams,
ClientRPCResponseResult,
Expand All @@ -22,13 +24,17 @@ class VaultsSecretsMkdir extends DuplexHandler<
> {
public handle = async function* (
input: AsyncIterableIterator<ClientRPCRequestParams<SecretDirMessage>>,
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue>,
ctx: ContextTimed,
): AsyncGenerator<ClientRPCResponseResult<SuccessOrErrorMessage>> {
const { db, vaultManager }: { db: DB; vaultManager: VaultManager } =
this.container;
let metadata: POJO;
yield* db.withTransactionG(
async function* (tran): AsyncGenerator<SuccessOrErrorMessage> {
for await (const secretDirMessage of input) {
ctx.signal.throwIfAborted();
// Unpack input
if (metadata == null) metadata = secretDirMessage.metadata ?? {};
const nameOrId = secretDirMessage.nameOrId;
Expand All @@ -41,10 +47,7 @@ class VaultsSecretsMkdir extends DuplexHandler<
throw new vaultsErrors.ErrorVaultsVaultUndefined();
}
// Write directories. This doesn't need to be grouped by vault names,
// as no commit is created for empty directories anyways. The
// vaultOps.mkdir() method also returns an object of type
// SuccessOrErrorMessage. As such, we can return the result without
// doing any type conversion or extra processing.
// as no commit is created for empty directories anyway.
yield await vaultManager.withVaults(
[vaultId],
async (vault) => {
Expand Down
11 changes: 9 additions & 2 deletions src/client/handlers/VaultsSecretsRemove.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import type { ContextTimed } from '@matrixai/contexts';
import type { DB } from '@matrixai/db';
import type { JSONValue } from '@matrixai/rpc';
import type { ResourceAcquire } from '@matrixai/resources';
import type {
ClientRPCRequestParams,
Expand Down Expand Up @@ -31,6 +33,9 @@ class VaultsSecretsRemove extends DuplexHandler<
SecretsRemoveHeaderMessage | SecretIdentifierMessageTagged
>
>,
_cancel: (reason?: any) => void,
_meta: Record<string, JSONValue>,
ctx: ContextTimed,
): AsyncGenerator<ClientRPCResponseResult<SuccessOrErrorMessage>> {
const { db, vaultManager }: { db: DB; vaultManager: VaultManager } =
this.container;
Expand All @@ -50,6 +55,7 @@ class VaultsSecretsRemove extends DuplexHandler<
const vaultAcquires = await db.withTransactionF(async (tran) => {
const vaultAcquires: Array<ResourceAcquire<FileSystemWritable>> = [];
for (const vaultName of headerMessage.vaultNames) {
ctx.signal.throwIfAborted();
const vaultIdFromName = await vaultManager.getVaultId(vaultName, tran);
const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(vaultName);
if (vaultId == null) {
Expand All @@ -76,6 +82,7 @@ class VaultsSecretsRemove extends DuplexHandler<
}
let loopRan = false;
for await (const message of input) {
ctx.signal.throwIfAborted();
loopRan = true;
// Header messages should not be seen anymore
if (message.type === 'VaultNamesHeaderMessage') {
Expand Down Expand Up @@ -108,8 +115,8 @@ class VaultsSecretsRemove extends DuplexHandler<
e.code === 'ENOTEMPTY' ||
e.code === 'EINVAL'
) {
// EINVAL can be triggered if removing the root of the
// vault is attempted.
// EINVAL can be triggered if removing the root of the vault is
// attempted.
yield {
type: 'error',
code: e.code,
Expand Down
4 changes: 1 addition & 3 deletions src/client/handlers/VaultsVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ class VaultsVersion extends UnaryHandler<
},
tran,
);
// Checking if latest version ID
const latestVersion = latestOid === currentVersionId;
return {
latestVersion,
latestVersion: latestOid === currentVersionId,
};
});
};
Expand Down
66 changes: 35 additions & 31 deletions src/vaults/VaultInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type RemoteInfo = {
};

interface VaultInternal extends CreateDestroyStartStop {}

@CreateDestroyStartStop(
new vaultsErrors.ErrorVaultRunning(),
new vaultsErrors.ErrorVaultDestroyed(),
Expand All @@ -61,40 +62,43 @@ class VaultInternal {
* If no state already exists then state for the vault is initialized.
* If state already exists then this just creates the `VaultInternal` instance for managing that state.
*/
public static async createVaultInternal({
vaultId,
vaultName,
db,
vaultsDbPath,
keyRing,
efs,
logger = new Logger(this.name),
fresh = false,
tran,
}: {
vaultId: VaultId;
vaultName?: VaultName;
db: DB;
vaultsDbPath: LevelPath;
keyRing: KeyRing;
efs: EncryptedFS;
logger?: Logger;
fresh?: boolean;
tran?: DBTransaction;
}): Promise<VaultInternal> {
public static async createVaultInternal(
{
vaultId,
vaultName,
db,
vaultsDbPath,
keyRing,
efs,
logger = new Logger(this.name),
fresh = false,
}: {
vaultId: VaultId;
vaultName?: VaultName;
db: DB;
vaultsDbPath: LevelPath;
keyRing: KeyRing;
efs: EncryptedFS;
logger?: Logger;
fresh?: boolean;
},
tran?: DBTransaction,
): Promise<VaultInternal> {
if (tran == null) {
return await db.withTransactionF((tran) =>
this.createVaultInternal({
vaultId,
vaultName,
db,
vaultsDbPath,
keyRing,
efs,
logger,
fresh,
this.createVaultInternal(
{
vaultId,
vaultName,
db,
vaultsDbPath,
keyRing,
efs,
logger,
fresh,
},
tran,
}),
),
);
}

Expand Down
41 changes: 23 additions & 18 deletions src/vaults/VaultManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type VaultMetadata = {
};

interface VaultManager extends CreateDestroyStartStop {}

@CreateDestroyStartStop(
new vaultsErrors.ErrorVaultManagerRunning(),
new vaultsErrors.ErrorVaultManagerDestroyed(),
Expand Down Expand Up @@ -343,17 +344,19 @@ class VaultManager {
[vaultId.toString(), RWLockWriter, 'write'],
async () => {
// Creating vault
const vault = await VaultInternal.createVaultInternal({
vaultId,
vaultName,
keyRing: this.keyRing,
efs: this.efs,
logger: this.logger.getChild(VaultInternal.name),
db: this.db,
vaultsDbPath: this.vaultsDbPath,
fresh: true,
const vault = await VaultInternal.createVaultInternal(
{
vaultId: vaultId,
vaultName: vaultName,
keyRing: this.keyRing,
efs: this.efs,
logger: this.logger.getChild(VaultInternal.name),
db: this.db,
vaultsDbPath: this.vaultsDbPath,
fresh: true,
},
tran,
});
);
// Adding vault to object map
this.vaultMap.set(vaultIdString, vault);
return vault.vaultId;
Expand Down Expand Up @@ -984,15 +987,17 @@ class VaultManager {
);
}
// 2. if the state exists then create, add to map and return that
const newVault = await VaultInternal.createVaultInternal({
vaultId,
keyRing: this.keyRing,
efs: this.efs,
logger: this.logger.getChild(VaultInternal.name),
db: this.db,
vaultsDbPath: this.vaultsDbPath,
const newVault = await VaultInternal.createVaultInternal(
{
vaultId: vaultId,
keyRing: this.keyRing,
efs: this.efs,
logger: this.logger.getChild(VaultInternal.name),
db: this.db,
vaultsDbPath: this.vaultsDbPath,
},
tran,
});
);
this.vaultMap.set(vaultIdString, newVault);
return newVault;
}
Expand Down

0 comments on commit 96acf2a

Please sign in to comment.