diff --git a/src/client/handlers/VaultsSecretsCat.ts b/src/client/handlers/VaultsSecretsCat.ts index 2770b3b0b..f98084de4 100644 --- a/src/client/handlers/VaultsSecretsCat.ts +++ b/src/client/handlers/VaultsSecretsCat.ts @@ -23,7 +23,7 @@ class VaultsSecretsCat extends DuplexHandler< ClientRPCResponseResult > { public handle = async function* ( - input: AsyncIterable>, + input: AsyncIterableIterator>, ): AsyncGenerator> { const { db, vaultManager }: { db: DB; vaultManager: VaultManager } = this.container; diff --git a/src/client/handlers/VaultsSecretsEnv.ts b/src/client/handlers/VaultsSecretsEnv.ts index acfc78119..58cb1b79d 100644 --- a/src/client/handlers/VaultsSecretsEnv.ts +++ b/src/client/handlers/VaultsSecretsEnv.ts @@ -10,7 +10,7 @@ import { DuplexHandler } from '@matrixai/rpc'; import * as vaultsUtils from '../../vaults/utils'; import * as vaultsErrors from '../../vaults/errors'; -class VaultsSecretsList extends DuplexHandler< +class VaultsSecretsEnv extends DuplexHandler< { db: DB; vaultManager: VaultManager; @@ -86,4 +86,4 @@ class VaultsSecretsList extends DuplexHandler< }; } -export default VaultsSecretsList; +export default VaultsSecretsEnv; diff --git a/src/client/handlers/VaultsSecretsMkdir.ts b/src/client/handlers/VaultsSecretsMkdir.ts index 9284c74e0..da8b2c00c 100644 --- a/src/client/handlers/VaultsSecretsMkdir.ts +++ b/src/client/handlers/VaultsSecretsMkdir.ts @@ -21,7 +21,7 @@ class VaultsSecretsMkdir extends DuplexHandler< ClientRPCResponseResult > { public handle = async function* ( - input: AsyncIterable>, + input: AsyncIterableIterator>, ): AsyncGenerator> { const { db, vaultManager }: { db: DB; vaultManager: VaultManager } = this.container; diff --git a/src/client/handlers/VaultsSecretsRemove.ts b/src/client/handlers/VaultsSecretsRemove.ts index bf57ba273..cbf4a7fb1 100644 --- a/src/client/handlers/VaultsSecretsRemove.ts +++ b/src/client/handlers/VaultsSecretsRemove.ts @@ -26,7 +26,7 @@ class VaultsSecretsRemove extends DuplexHandler< ClientRPCResponseResult > { public handle = async function* ( - input: AsyncIterable< + input: AsyncIterableIterator< ClientRPCRequestParams< SecretsRemoveHeaderMessage | SecretIdentifierMessageTagged > @@ -34,18 +34,19 @@ class VaultsSecretsRemove extends DuplexHandler< ): AsyncGenerator> { const { db, vaultManager }: { db: DB; vaultManager: VaultManager } = this.container; - const vaultAcquires: Array> = []; - // Extracts the header message from the iterator - const headerMessage = await (async () => { - const iterator = input[Symbol.asyncIterator](); - const header = (await iterator.next()).value; - if (header.type === 'VaultNamesHeaderMessage') { - if (header == null) throw new clientErrors.ErrorClientInvalidHeader(); - return header; - } - })(); + // Extract the header message from the iterator + const headerMessage: + | SecretsRemoveHeaderMessage + | SecretIdentifierMessageTagged = (await input.next()).value; + if ( + headerMessage == null || + headerMessage.type !== 'VaultNamesHeaderMessage' + ) { + throw new clientErrors.ErrorClientInvalidHeader(); + } // Create an array of write acquires - await db.withTransactionF(async (tran) => { + const vaultAcquires = await db.withTransactionF(async (tran) => { + const vaultAcquires: Array> = []; for (const vaultName of headerMessage.vaultNames) { const vaultIdFromName = await vaultManager.getVaultId(vaultName, tran); const vaultId = vaultIdFromName ?? vaultsUtils.decodeVaultId(vaultName); @@ -60,6 +61,7 @@ class VaultsSecretsRemove extends DuplexHandler< ); vaultAcquires.push(acquire); } + return vaultAcquires; }); // Acquire all locks in parallel and perform all operations at once yield* withG( @@ -72,7 +74,11 @@ class VaultsSecretsRemove extends DuplexHandler< } for await (const message of input) { // Ignoring any header messages - if (message.type !== 'SecretIdentifierMessage') continue; + if (message.type === 'VaultNamesHeaderMessage') { + throw new clientErrors.ErrorClientInvalidHeader( + 'The header message cannot be sent multiple times', + ); + } const efs = vaultMap.get(message.nameOrId); if (efs == null) { throw new vaultsErrors.ErrorVaultsVaultUndefined( @@ -98,7 +104,7 @@ class VaultsSecretsRemove extends DuplexHandler< e.code === 'ENOTEMPTY' || e.code === 'EINVAL' ) { - // INVAL can be triggered if removing the root of the + // EINVAL can be triggered if removing the root of the // vault is attempted. yield { type: 'error', diff --git a/src/git/utils.ts b/src/git/utils.ts index c80b956bc..cda1cbd94 100644 --- a/src/git/utils.ts +++ b/src/git/utils.ts @@ -218,7 +218,7 @@ async function listObjects({ } return; default: - utils.never(); + utils.never('Invalid type'); } } diff --git a/src/utils/utils.ts b/src/utils/utils.ts index cd4dbeda4..d14329739 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -48,7 +48,7 @@ function getDefaultNodePath(): string | undefined { return p; } -function never(message?: string): never { +function never(message: string): never { throw new utilsErrors.ErrorUtilsUndefinedBehaviour(message); } diff --git a/src/vaults/VaultInternal.ts b/src/vaults/VaultInternal.ts index b896d3ce1..2c700178d 100644 --- a/src/vaults/VaultInternal.ts +++ b/src/vaults/VaultInternal.ts @@ -571,7 +571,7 @@ class VaultInternal { } // The returned transaction can be undefined, too. We won't handle those // cases. - if (tran == null) utils.never(); + if (tran == null) utils.never('Acquired transactions cannot be null'); await tran.lock( [...this.vaultMetadataDbPath, VaultInternal.dirtyKey].join(''), ); diff --git a/tests/client/handlers/vaults.test.ts b/tests/client/handlers/vaults.test.ts index 57b256cb3..7b05bb6cc 100644 --- a/tests/client/handlers/vaults.test.ts +++ b/tests/client/handlers/vaults.test.ts @@ -1453,6 +1453,7 @@ describe('vaultsSecretsMkdir', () => { const vaultName = 'test-vault'; const vaultId = await vaultManager.createVault(vaultName); const dirPath = 'dir/dir1/dir2'; + // Attempt to make directories const response = await rpcClient.methods.vaultsSecretsMkdir(); const writer = response.writable.getWriter(); await writer.write({ @@ -1461,7 +1462,7 @@ describe('vaultsSecretsMkdir', () => { metadata: { options: { recursive: true } }, }); await writer.close(); - + // Check if the operation concluded as expected for await (const data of response.readable) { expect(data.type).toEqual('success'); } @@ -1476,13 +1477,15 @@ describe('vaultsSecretsMkdir', () => { const vaultId = await vaultManager.createVault(vaultName); const encodeVaultId = vaultsUtils.encodeVaultId(vaultId); const dirPath = 'dir/dir1/dir2'; + // Attempt to make directories const response = await rpcClient.methods.vaultsSecretsMkdir(); const writer = response.writable.getWriter(); await writer.write({ nameOrId: encodeVaultId, dirName: dirPath }); await writer.close(); + // Check if the operation concluded as expected for await (const data of response.readable) { expect(data.type).toEqual('error'); - if (data.type !== 'error') utils.never(); + if (data.type !== 'error') utils.never("Type is asserted to be 'error'"); expect(data.code).toEqual('ENOENT'); expect(data.reason).toEqual(dirPath); } @@ -1543,17 +1546,21 @@ describe('vaultsSecretsMkdir', () => { // Attempt to make directories const response = await rpcClient.methods.vaultsSecretsMkdir(); const writer = response.writable.getWriter(); - await writer.write({ nameOrId: vaultIdEncoded1, dirName: dirPath1 }); - await writer.write({ nameOrId: vaultIdEncoded2, dirName: dirPath2 }); await writer.write({ nameOrId: vaultIdEncoded1, dirName: dirPath3 }); + await writer.write({ nameOrId: vaultIdEncoded2, dirName: dirPath2 }); + await writer.write({ nameOrId: vaultIdEncoded1, dirName: dirPath1 }); await writer.close(); // Check if the operation concluded as expected + let successCount = 0; for await (const data of response.readable) { if (data.type === 'error') { expect(data.code).toEqual('ENOENT'); expect(data.reason).toEqual(dirPath3); + } else { + successCount++; } } + expect(successCount).toEqual(2); await vaultManager.withVaults( [vaultId1, vaultId2], async (vault1, vault2) => { @@ -1585,7 +1592,7 @@ describe('vaultsSecretsMkdir', () => { // Check if the operation concluded as expected for await (const data of response.readable) { expect(data.type).toEqual('error'); - if (data.type !== 'error') utils.never(); + if (data.type !== 'error') utils.never("Type is asserted to be 'error'"); expect(data.code).toEqual('EEXIST'); expect(data.reason).toEqual(dirPath); } @@ -1728,7 +1735,9 @@ describe('vaultsSecretsCat', () => { // Read response for await (const data of response.readable) { expect(data.type).toEqual('success'); - if (data.type !== 'success') utils.never(); + if (data.type !== 'success') { + utils.never("Type is asserted to be 'success'"); + } expect(data.secretContent).toEqual(secretContent); } }); @@ -1747,7 +1756,7 @@ describe('vaultsSecretsCat', () => { // Read response for await (const data of response.readable) { expect(data.type).toEqual('error'); - if (data.type !== 'error') utils.never(); + if (data.type !== 'error') utils.never("Type is asserted to be 'error'"); expect(data.code).toEqual('ENOENT'); expect(data.reason).toEqual(secretName); } @@ -1773,7 +1782,7 @@ describe('vaultsSecretsCat', () => { // Read response for await (const data of response.readable) { expect(data.type).toEqual('error'); - if (data.type !== 'error') utils.never(); + if (data.type !== 'error') utils.never("Type is asserted to be 'error'"); expect(data.code).toEqual('EISDIR'); expect(data.reason).toEqual(secretName); } @@ -1803,7 +1812,9 @@ describe('vaultsSecretsCat', () => { let totalContent = ''; for await (const data of response.readable) { expect(data.type).toEqual('success'); - if (data.type !== 'success') utils.never(); + if (data.type !== 'success') { + utils.never("Type is asserted to be 'success'"); + } totalContent += data.secretContent; } expect(totalContent).toEqual(`${secretContent1}${secretContent2}`); @@ -1845,7 +1856,9 @@ describe('vaultsSecretsCat', () => { let totalContent = ''; for await (const data of response.readable) { expect(data.type).toEqual('success'); - if (data.type !== 'success') utils.never(); + if (data.type !== 'success') { + utils.never("Type is asserted to be 'success'"); + } totalContent += data.secretContent; } expect(totalContent).toEqual( @@ -2397,7 +2410,7 @@ describe('vaultsSecretsRemove', () => { for await (const data of response.readable) { loopRun = true; expect(data.type).toStrictEqual('error'); - if (data.type !== 'error') utils.never(); + if (data.type !== 'error') utils.never("Type is asserted to be 'error'"); expect(data.code).toStrictEqual('EINVAL'); } // Check