diff --git a/src/client/callers/vaultsSecretsGet.ts b/src/client/callers/vaultsSecretsGet.ts index 5f4a6b541..7e7172255 100644 --- a/src/client/callers/vaultsSecretsGet.ts +++ b/src/client/callers/vaultsSecretsGet.ts @@ -1,10 +1,10 @@ import type { HandlerTypes } from '@matrixai/rpc'; import type VaultsSecretsGet from '../handlers/VaultsSecretsGet'; -import { UnaryCaller } from '@matrixai/rpc'; +import { ServerCaller } from '@matrixai/rpc'; type CallerTypes = HandlerTypes; -const vaultsSecretsGet = new UnaryCaller< +const vaultsSecretsGet = new ServerCaller< CallerTypes['input'], CallerTypes['output'] >(); diff --git a/src/client/handlers/VaultsSecretsGet.ts b/src/client/handlers/VaultsSecretsGet.ts index 448c10248..645bfdfdf 100644 --- a/src/client/handlers/VaultsSecretsGet.ts +++ b/src/client/handlers/VaultsSecretsGet.ts @@ -3,27 +3,32 @@ import type { ClientRPCRequestParams, ClientRPCResponseResult, ContentMessage, - SecretIdentifierMessage, + SecretCatMessage, } from '../types'; import type VaultManager from '../../vaults/VaultManager'; -import { UnaryHandler } 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 UnaryHandler< +class VaultsSecretsGet extends ServerHandler< { vaultManager: VaultManager; db: DB; }, - ClientRPCRequestParams, + ClientRPCRequestParams, ClientRPCResponseResult > { - public handle = async ( - input: ClientRPCRequestParams, - ): Promise> => { + public async *handle( + input: ClientRPCRequestParams, + ): AsyncGenerator, void, void> { const { vaultManager, db } = this.container; - return await db.withTransactionF(async (tran) => { + + yield* db.withTransactionG(async function* (tran): AsyncGenerator< + ContentMessage, + void, + void + > { const vaultIdFromName = await vaultManager.getVaultId( input.nameOrId, tran, @@ -33,18 +38,21 @@ class VaultsSecretsGet extends UnaryHandler< if (vaultId == null) { throw new vaultsErrors.ErrorVaultsVaultUndefined(); } - const secretContent = await vaultManager.withVaults( + yield* vaultManager.withVaultsG( [vaultId], - async (vault) => { - return await vaultOps.getSecret(vault, input.secretName); + async function* (vault): AsyncGenerator { + for (const secretName of input.secretNames) { + yield { + secretContent: ( + await vaultOps.getSecret(vault, secretName) + ).toString('binary'), + }; + } }, tran, ); - return { - secretContent: secretContent.toString('binary'), - }; }); - }; + } } export default VaultsSecretsGet; diff --git a/src/client/types.ts b/src/client/types.ts index 0b125b18d..8c0125c75 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -306,6 +306,10 @@ type SecretPathMessage = { type SecretIdentifierMessage = VaultIdentifierMessage & SecretPathMessage; +type SecretCatMessage = VaultIdentifierMessage & { + secretNames: Array; +}; + // Contains binary content as a binary string 'toString('binary')' type ContentMessage = { secretContent: string; @@ -417,6 +421,7 @@ export type { SecretPathMessage, SecretIdentifierMessage, ContentMessage, + SecretCatMessage, SecretContentMessage, SecretMkdirMessage, SecretDirMessage, diff --git a/tests/client/handlers/vaults.test.ts b/tests/client/handlers/vaults.test.ts index b847ee018..d7e5e2fe6 100644 --- a/tests/client/handlers/vaults.test.ts +++ b/tests/client/handlers/vaults.test.ts @@ -1449,12 +1449,16 @@ describe('vaultsSecretsNew and vaultsSecretsDelete, vaultsSecretsGet', () => { }); expect(createResponse.success).toBeTruthy(); // Get secret - const getResponse1 = await rpcClient.methods.vaultsSecretsGet({ + const getResponse = await rpcClient.methods.vaultsSecretsGet({ nameOrId: vaultIdEncoded, - secretName: secret, + secretNames: [secret], }); - const secretContent = getResponse1.secretContent; - expect(secretContent).toStrictEqual(secret); + const secretContent: Array = []; + for await (const data of getResponse) { + secretContent.push(data.secretContent); + } + const concatenatedContent = secretContent.join(''); + expect(concatenatedContent).toStrictEqual(secret); // Delete secret const deleteResponse = await rpcClient.methods.vaultsSecretsDelete({ nameOrId: vaultIdEncoded, @@ -1462,13 +1466,41 @@ describe('vaultsSecretsNew and vaultsSecretsDelete, vaultsSecretsGet', () => { }); expect(deleteResponse.success).toBeTruthy(); // Check secret was deleted - await testsUtils.expectRemoteError( - rpcClient.methods.vaultsSecretsGet({ + const deleteGetResponse = await rpcClient.methods.vaultsSecretsGet({ + nameOrId: vaultIdEncoded, + secretNames: [secret], + }); + await expect(async () => { + try { + for await (const _ of deleteGetResponse); + } catch (e) { + throw e.cause; + } + }).rejects.toThrow(vaultsErrors.ErrorSecretsSecretUndefined); + }); + test('concatenates multiple secrets together', async () => { + // Create secret + const secretNames = ['test-secret1', 'test-secret2', 'test-secret3']; + const vaultId = await vaultManager.createVault('test-vault'); + const vaultIdEncoded = vaultsUtils.encodeVaultId(vaultId); + for (const secretName of secretNames) { + const createResponse = await rpcClient.methods.vaultsSecretsNew({ nameOrId: vaultIdEncoded, - secretName: secret, - }), - vaultsErrors.ErrorSecretsSecretUndefined, - ); + secretName: secretName, + secretContent: Buffer.from(secretName).toString('binary'), + }); + expect(createResponse.success).toBeTruthy(); + } + // Get secret + const getResponse = await rpcClient.methods.vaultsSecretsGet({ + nameOrId: vaultIdEncoded, + secretNames: secretNames, + }); + const secretContent: Array = []; + for await (const data of getResponse) { + secretContent.push(data.secretContent); + } + expect(secretContent.join('')).toStrictEqual(secretNames.join('')); }); }); describe('vaultsSecretsNewDir and vaultsSecretsList', () => {