@unikvs/checksum
How to use @unikvs/checksum middleware, which hashes byte sequences and verifies them against expectations.
Overview
Middleware that hashes byte sequences and verifies them against expected values.Middleware
It passes data through unchanged and only verifies when a checksum var holds an expected hash. Six variants exist: MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512.
- Each concrete class’s
namematches the class name (e.g."ChecksumSha256"). isOpenis alwaystrue.
Install with:
npm install @unikvs/checksum @noble/hashes@2.0.0pnpm add @unikvs/checksum @noble/hashes@2.0.0yarn add @unikvs/checksum @noble/hashes@2.0.0bun add @unikvs/checksum @noble/hashes@2.0.0nub add @unikvs/checksum @noble/hashes@2.0.0aube add @unikvs/checksum @noble/hashes@2.0.0Usage
ChecksumSha256 implements IMiddleware. Pass it to UniKvs with use().
import { ChecksumSha256 } from "@unikvs/checksum";
The other five work the same way. Constructor arguments:
required?boolean
Whether to throw when no checksum var is present. Defaults to `false`.
booleanThe following stores data with an expected SHA-256 hash and verifies it on reads:
import { ChecksumSha256 } from "@unikvs/checksum";
import { Memory } from "@unikvs/memory";
import * as unikvs from "unikvs";
const kvs = new unikvs.Builder<{ file: unikvs.Value<Uint8Array> }>()
.use(new ChecksumSha256())
.persist(new Memory())
.build();
await kvs.open();
const data = new TextEncoder().encode("abc");
const sha256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";
await kvs.set("file", data, {
vars: { "@unikvs/checksum:sha256": sha256 },
});
const file = await kvs.get("file", {
vars: { "@unikvs/checksum:sha256": sha256 },
});
await kvs.close();
Checksum
Abstract base class for the six variants. Never use it directly; use a concrete class.
CHECKSUM_ON_HASH_VAR_NAME is the name of the callback var that receives the computed hash. Its value is CHECKSUM_VAR_NAME followed by :onHash.
ChecksumMd5
Middleware verifying with MD5. The checksum var is "@unikvs/checksum:md5".
ChecksumSha1
Middleware verifying with SHA-1. The checksum var is "@unikvs/checksum:sha1".
ChecksumSha224
Middleware verifying with SHA-224. The checksum var is "@unikvs/checksum:sha224".
ChecksumSha256
Middleware verifying with SHA-256. The checksum var is "@unikvs/checksum:sha256".
ChecksumSha384
Middleware verifying with SHA-384. The checksum var is "@unikvs/checksum:sha384".
ChecksumSha512
Middleware verifying with SHA-512. The checksum var is "@unikvs/checksum:sha512".
IHasher
Interface for incremental hash computation. Matches @noble/hashes hashers.
IHash
Interface holding a one-shot hash function and a create hasher factory.
create() => IHasher
Creates a hasher for incremental computation.
() => IHasherChecksumOnHash
Callback that receives the computed hash. Pass a function in the "<CHECKSUM_VAR_NAME>:onHash" var, separate from the checksum var. For SHA-256, that is "@unikvs/checksum:sha256:onHash".
The callback’s this is bound to the middleware instance. The first argument is the execution context and the second argument is the computed hash.
The callback is called when hashing and verification succeed. If you specify only the callback without an expected checksum, the middleware still computes the hash and calls the callback. If required is true and no expected checksum is present, it throws ChecksumRequiredError and does not call the callback.
The following example receives the SHA-256 hash during a write.
const hashes: string[] = [];
await kvs.set("file", data, {
vars: {
"@unikvs/checksum:sha256:onHash": function (
this: ChecksumSha256,
c: IPipelineContext,
hash: string,
): void {
hashes.push(hash);
},
},
});
If the callback value is not a function, the middleware throws ChecksumInvalidOnHashError. Exceptions or rejections thrown by the callback propagate as operation failures.
Data types
| Method | Input | Output |
|---|---|---|
encode |
Uint8Array<ArrayBuffer> |
Uint8Array<ArrayBuffer> |
decode |
Uint8Array<ArrayBuffer> |
Uint8Array<ArrayBuffer> |
encodeStream |
Uint8Array<ArrayBuffer> |
Uint8Array<ArrayBuffer> |
decodeStream |
Uint8Array<ArrayBuffer> |
Uint8Array<ArrayBuffer> |
encodeanddecodepass data through unchanged.- This middleware computes the hash (lowercase hex) when the matching checksum var holds a string or when the
onHashcallback is specified. - It throws when the value does not match the expectation.
- It throws when no checksum var exists and
requiredistrue, even if theonHashcallback is specified. - The
onHashcallback’sthisis bound to the middleware instance. It receives the execution context as the first argument and the computed hash (lowercase hex) as the second argument. If the callback returns aPromise, the middleware waits for it. encodeStreamanddecodeStreamstream chunks downstream unchanged while updating the hash, verifying on completion, and calling theonHashcallback.
Errors
Errors thrown by this package:
ChecksumMismatchError
Thrown when the computed hash does not match the expectation.
Meaning
Either the data or the expectation is wrong.
How to fix
Check which of the data and the expected hash is correct.
ChecksumRequiredError
Meaning
Thrown when required is true but no checksum var was given.
How to fix
Set the expected hash in the matching checksum var, or set required to false.
ChecksumInvalidVarNameError
Thrown when a checksum var name is not a string.
actualunknown
The given var-name value.
unknownMeaning
This is a usage error, so it extends InvalidUsageErrorBase. meta.actual keeps the given value as-is.
How to fix
This never happens when using the published concrete classes as-is. In a custom subclass, set CHECKSUM_VAR_NAME to a string.
ChecksumInvalidOnHashError
Thrown when the "<CHECKSUM_VAR_NAME>:onHash" value is not a function.
actualunknown
The given callback value.
unknownMeaning
This is a usage error, so it extends InvalidUsageErrorBase. meta.actual keeps the given value as-is.
How to fix
Set a function in the onHash var, or omit the var.
ChecksumInvalidRequiredError
Thrown when required is not a boolean.
actualunknown
The given `required` value.
unknownMeaning
This is a usage error, so it extends InvalidUsageErrorBase. meta.actual keeps the given value as-is.
How to fix
Pass true or false to required. It defaults to false.