commit 6352bdad026d8944f3dc93728e51c05ea11fc79b
parent 83861a25156ce96428a382c11c56bab799513c30
Author: Florian Dold <dold@taler.net>
Date: Thu, 3 Sep 2026 15:30:14 +0200
idb-bridge: read key characters past the truncated zero bytes
Serialized keys drop trailing zero bytes, and a multi-byte character
can end in one, so the reader must pad with zeros instead of reading
past the buffer.
Diffstat:
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/packages/idb-bridge/src/util/key-storage.ts b/packages/idb-bridge/src/util/key-storage.ts
@@ -217,6 +217,18 @@ export function serializeKey(key: IDBValidKey): Uint8Array {
return buf;
}
+/**
+ * Same as DataView.getUint8, but read zero past the end of the
+ * buffer. Serialized keys have their trailing zero bytes removed,
+ * and a multi-byte character can end in one.
+ */
+function getUint8Trunc(dv: DataView, offset: number): number {
+ if (offset >= dv.byteLength) {
+ return 0;
+ }
+ return dv.getUint8(offset);
+}
+
function internalReadString(dv: DataView, offset: number): [number, string] {
const chars: string[] = [];
while (offset < dv.byteLength) {
@@ -229,13 +241,13 @@ function internalReadString(dv: DataView, offset: number): [number, string] {
let c: number;
if ((v & threeByteMask) === threeByteMask) {
const b1 = v & ~threeByteMask;
- const b2 = dv.getUint8(offset + 1);
- const b3 = dv.getUint8(offset + 2);
+ const b2 = getUint8Trunc(dv, offset + 1);
+ const b3 = getUint8Trunc(dv, offset + 2);
c = (b1 << 10) | (b2 << 2) | (b3 >> 6);
offset += 3;
} else if ((v & twoByteMask) === twoByteMask) {
const b1 = v & ~twoByteMask;
- const b2 = dv.getUint8(offset + 1);
+ const b2 = getUint8Trunc(dv, offset + 1);
c = ((b1 << 8) | b2) + twoByteOffset;
offset += 2;
} else {
@@ -244,7 +256,7 @@ function internalReadString(dv: DataView, offset: number): [number, string] {
}
chars.push(String.fromCharCode(c));
}
- return [offset, chars.join("")];
+ return [Math.min(offset, dv.byteLength), chars.join("")];
}
function internalReadBytes(dv: DataView, offset: number): [number, Uint8Array] {
@@ -267,13 +279,13 @@ function internalReadBytes(dv: DataView, offset: number): [number, Uint8Array] {
let c: number;
if ((v & threeByteMask) === threeByteMask) {
const b1 = v & ~threeByteMask;
- const b2 = dv.getUint8(offset + 1);
- const b3 = dv.getUint8(offset + 2);
+ const b2 = getUint8Trunc(dv, offset + 1);
+ const b3 = getUint8Trunc(dv, offset + 2);
c = (b1 << 10) | (b2 << 2) | (b3 >> 6);
offset += 3;
} else if ((v & twoByteMask) === twoByteMask) {
const b1 = v & ~twoByteMask;
- const b2 = dv.getUint8(offset + 1);
+ const b2 = getUint8Trunc(dv, offset + 1);
c = ((b1 << 8) | b2) + twoByteOffset;
offset += 2;
} else {
@@ -283,7 +295,7 @@ function internalReadBytes(dv: DataView, offset: number): [number, Uint8Array] {
bytes[writePos] = c;
writePos++;
}
- return [offset, bytes];
+ return [Math.min(offset, dv.byteLength), bytes];
}
/**