taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

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:
Mpackages/idb-bridge/src/util/key-storage.ts | 28++++++++++++++++++++--------
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]; } /**