Skip to content

Commit

Permalink
chore: updated VaultsSecretsRemove to use new resource aquisition
Browse files Browse the repository at this point in the history
  • Loading branch information
aryanjassal committed Nov 27, 2024
1 parent f7f3589 commit ddc512e
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 213 deletions.
180 changes: 46 additions & 134 deletions src/client/handlers/VaultsSecretsRemove.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { DB } from '@matrixai/db';
import { ResourceAcquire, withG } from '@matrixai/resources';
import type {
ClientRPCRequestParams,
ClientRPCResponseResult,
Expand All @@ -8,12 +7,12 @@ import type {
SuccessOrErrorMessage,
} from '../types';
import type VaultManager from '../../vaults/VaultManager';
import { ResourceAcquire, withG } from '@matrixai/resources';
import { DuplexHandler } from '@matrixai/rpc';
import { FileSystemWritable } from '../../vaults/types';
import * as vaultsUtils from '../../vaults/utils';
import * as vaultsErrors from '../../vaults/errors';
import * as clientErrors from '../errors';
import { FileSystemWritable } from '../../vaults/types';
import * as utils from '../../utils';

class VaultsSecretsRemove extends DuplexHandler<
{
Expand All @@ -37,33 +36,28 @@ class VaultsSecretsRemove extends DuplexHandler<
const vaultAcquires: Array<ResourceAcquire<FileSystemWritable>> = [];
// Extracts the header message from the iterator
const headerMessage = await (async () => {
let header: SecretsRemoveHeaderMessage | undefined;
for await (const value of input) {
// TS cannot properly narrow down this type as it is too deeply wrapped.
// The as keyword is used to help it with type narrowing.
const message = value as
| SecretIdentifierMessageTagged
| SecretsRemoveHeaderMessage;
if (message.type === 'VaultNamesHeaderMesage') header = message;
break;
const iterator = input[Symbol.asyncIterator]();
const header = (await iterator.next()).value;
if (header.type === 'VaultNamesHeaderMessage') {
if (header == null) throw new clientErrors.ErrorClientInvalidHeader();
return header;
}
// The header message is mandatory
if (header == null) throw new clientErrors.ErrorClientInvalidHeader();
return header;
})();
// Create an array of write acquires
await db.withTransactionF(async (tran) => {
for (const vaultName of headerMessage!.vaultNames) {
for (const vaultName of headerMessage.vaultNames) {
const vaultIdFromName = await vaultManager.getVaultId(vaultName, tran);
const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(vaultName);
if (vaultId == null) {
throw new vaultsErrors.ErrorVaultsVaultUndefined(
`Vault ${vaultName} does not exist`,
);
}
await vaultManager.withVaults([vaultId], async (vault) => {
vaultAcquires.push(vault.acquireWrite());
});
const acquire = await vaultManager.withVaults(
[vaultId],
async (vault) => vault.acquireWrite(),
);
vaultAcquires.push(acquire);
}
});
// Acquire all locks in parallel and perform all operations at once
Expand All @@ -75,130 +69,48 @@ class VaultsSecretsRemove extends DuplexHandler<
for (let i = 0; i < efses.length; i++) {
vaultMap.set(headerMessage!.vaultNames[i], efses[i]);
}
for await (const value of input) {
// TS cannot properly narrow down this type as it is too deeply wrapped.
// The as keyword is used to help it with type narrowing.
const message = value as
| SecretIdentifierMessageTagged
| SecretsRemoveHeaderMessage;
for await (const message of input) {
// Ignoring any header messages
if (message.type === 'SecretIdentifierMessage') {
const efs = vaultMap.get(message.nameOrId);
if (efs == null) {
throw new vaultsErrors.ErrorVaultsVaultUndefined(
`Vault ${message.nameOrId} was not present in the header message`,
);
if (message.type !== 'SecretIdentifierMessage') continue;
const efs = vaultMap.get(message.nameOrId);
if (efs == null) {
throw new vaultsErrors.ErrorVaultsVaultUndefined(
`Vault ${message.nameOrId} was not present in the header message`,
);
}
try {
const stat = await efs.stat(message.secretName);
if (stat.isDirectory()) {
await efs.rmdir(message.secretName, {
recursive: headerMessage.recursive,
});
} else {
await efs.unlink(message.secretName);
}
try {
const stat = await efs.stat(message.secretName);
if (stat.isDirectory()) {
await efs.rmdir(message.secretName, {
recursive: headerMessage.recursive,
});
} else {
await efs.unlink(message.secretName);
}
yield {
type: 'success',
success: true,
};
} catch (e) {
if (
e.code === 'ENOENT' ||
e.code === 'ENOTEMPTY' ||
e.code === 'EINVAL'
) {
// INVAL can be triggered if removing the root of the
// vault is attempted.
yield {
type: 'success',
success: true,
type: 'error',
code: e.code,
reason: message.secretName,
};
} catch (e) {
if (
e.code === 'ENOENT' ||
e.code === 'ENOTEMPTY' ||
e.code === 'EINVAL'
) {
// INVAL can be triggered if removing the root of the
// vault is attempted.
yield {
type: 'error',
code: e.code,
reason: message.secretName,
};
} else {
throw e;
}
} else {
throw e;
}
}
}
},
);

// Create a record of secrets to be removed, grouped by vault names
// const vaultGroups: Record<string, Array<string>> = {};
// const secretNames: Array<[string, string]> = [];
// let metadata: any = undefined;
// for await (const secretRemoveMessage of input) {
// if (metadata == null) metadata = secretRemoveMessage.metadata ?? {};
// secretNames.push([
// secretRemoveMessage.nameOrId,
// secretRemoveMessage.secretName,
// ]);
// }
// secretNames.forEach(([vaultName, secretName]) => {
// if (vaultGroups[vaultName] == null) {
// vaultGroups[vaultName] = [];
// }
// vaultGroups[vaultName].push(secretName);
// });
// Now, all the paths will be removed for a vault within a single commit
// yield* db.withTransactionG(
// async function* (tran): AsyncGenerator<SuccessOrErrorMessage> {
// for (const [vaultName, secretNames] of Object.entries(vaultGroups)) {
// const vaultIdFromName = await vaultManager.getVaultId(
// vaultName,
// tran,
// );
// const vaultId =
// vaultIdFromName ?? vaultsUtils.decodeVaultId(vaultName);
// if (vaultId == null) {
// throw new vaultsErrors.ErrorVaultsVaultUndefined();
// }
// yield* vaultManager.withVaultsG(
// [vaultId],
// async function* (vault): AsyncGenerator<SuccessOrErrorMessage> {
// yield* vault.writeG(
// async function* (efs): AsyncGenerator<SuccessOrErrorMessage> {
// for (const secretName of secretNames) {
// try {
// const stat = await efs.stat(secretName);
// if (stat.isDirectory()) {
// await efs.rmdir(secretName, {
// recursive: metadata?.options?.recursive,
// });
// } else {
// await efs.unlink(secretName);
// }
// yield {
// type: 'success',
// success: true,
// };
// } catch (e) {
// if (
// e.code === 'ENOENT' ||
// e.code === 'ENOTEMPTY' ||
// e.code === 'EINVAL'
// ) {
// // INVAL can be triggered if removing the root of the
// // vault is attempted.
// yield {
// type: 'error',
// code: e.code,
// reason: secretName,
// };
// } else {
// throw e;
// }
// }
// }
// },
// );
// },
// tran,
// );
// }
// },
// );
};
}

Expand Down
24 changes: 18 additions & 6 deletions src/client/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type {
ClientManifest,
JSONObject,
JSONRPCResponseResult,
JSONRPCResponseMetadata,
// JSONRPCResponseResult,
RPCClient,
} from '@matrixai/rpc';
import type {
Expand All @@ -25,6 +26,17 @@ import type {
} from '../nodes/types';
import type { AuditEventsGetTypeOverride } from './callers/auditEventsGet';

// TEMP: For testing and debugging. This will go into js-rpc or something.
type JSONRPCResponseResult<
T extends JSONObject = JSONObject,
M extends JSONObject = JSONObject,
> = T & {
metadata?: JSONRPCResponseMetadata &
M &
(T extends { metadata: infer U } ? U : {}) &
JSONObject;
};

type ClientRPCRequestParams<T extends JSONObject = JSONObject> =
JSONRPCResponseResult<
T,
Expand Down Expand Up @@ -362,14 +374,14 @@ type SecretStatMessage = {

type SecretIdentifierMessageTagged = SecretIdentifierMessage & {
type: 'SecretIdentifierMessage';
}
};

type VaultNamesHeaderMesage = {
type: 'VaultNamesHeaderMesage';
type VaultNamesHeaderMessage = {
type: 'VaultNamesHeaderMessage';
vaultNames: Array<string>;
};

type SecretsRemoveHeaderMessage = VaultNamesHeaderMesage & {
type SecretsRemoveHeaderMessage = VaultNamesHeaderMessage & {
recursive?: boolean;
};

Expand Down Expand Up @@ -449,7 +461,7 @@ export type {
SecretFilesMessage,
SecretStatMessage,
SecretIdentifierMessageTagged,
VaultNamesHeaderMesage,
VaultNamesHeaderMessage,
SecretsRemoveHeaderMessage,
SignatureMessage,
OverrideRPClientType,
Expand Down
Loading

0 comments on commit ddc512e

Please sign in to comment.