UNPKG

@hazae41/kdbx

Version:

Rust-like KeePass (KDBX 4) file format for TypeScript

133 lines (130 loc) 4.38 kB
import { Opaque, Readable, Writable } from '@hazae41/binary'; import { Vector } from '../../vector/index.mjs'; import { Cipher } from './cipher/index.mjs'; import { KeePassFile } from './markup/index.mjs'; class HeadersAndContentWithBytes { headers; content; constructor(headers, content) { this.headers = headers; this.content = content; } static computeOrThrow(headers, content) { const contentWithBytes = ContentWithBytes.computeOrThrow(content); return new HeadersAndContentWithBytes(headers, contentWithBytes); } async rotateOrThrow() { return new HeadersAndContentWithBytes(await this.headers.rotateOrThrow(), this.content); } sizeOrThrow() { return this.headers.sizeOrThrow() + this.content.sizeOrThrow(); } writeOrThrow(cursor) { this.headers.writeOrThrow(cursor); this.content.writeOrThrow(cursor); } recomputeOrThrow() { return HeadersAndContentWithBytes.computeOrThrow(this.headers, this.content.value); } } class ContentWithBytes { bytes; value; constructor(bytes, value) { this.bytes = bytes; this.value = value; } static computeOrThrow(content) { const string = new XMLSerializer().serializeToString(content.document); const opaque = new Opaque(new TextEncoder().encode(string)); return new ContentWithBytes(opaque, content); } sizeOrThrow() { return this.bytes.sizeOrThrow(); } writeOrThrow(cursor) { this.bytes.writeOrThrow(cursor); } recomputeOrThrow() { return ContentWithBytes.computeOrThrow(this.value); } } (function (ContentWithBytes) { function readOrThrow(cursor) { const bytes = new Opaque(cursor.readOrThrow(cursor.remaining)); const raw = new TextDecoder().decode(bytes.bytes); const xml = new DOMParser().parseFromString(raw, "text/xml"); return new ContentWithBytes(bytes, new KeePassFile(xml)); } ContentWithBytes.readOrThrow = readOrThrow; })(ContentWithBytes || (ContentWithBytes = {})); (function (HeadersAndContentWithBytes) { function readOrThrow(cursor) { const headers = Headers.readOrThrow(cursor); const content = ContentWithBytes.readOrThrow(cursor); return new HeadersAndContentWithBytes(headers, content); } HeadersAndContentWithBytes.readOrThrow = readOrThrow; })(HeadersAndContentWithBytes || (HeadersAndContentWithBytes = {})); class Headers { value; constructor(value) { this.value = value; } get cipher() { return this.value.value[1][0]; } get key() { return this.value.value[2][0]; } get binary() { return this.value.value[3]; } sizeOrThrow() { return this.value.sizeOrThrow(); } writeOrThrow(cursor) { this.value.writeOrThrow(cursor); } cloneOrThrow() { return Readable.readFromBytesOrThrow(Headers, Writable.writeToBytesOrThrow(this)); } async rotateOrThrow() { const { cipher, binary } = this; const key = new Opaque(new Uint8Array(crypto.getRandomValues(new Uint8Array(32)))); return Headers.initOrThrow({ cipher, key, binary }); } async getCipherOrThrow() { return await this.cipher.initOrThrow(this.key.bytes); } } (function (Headers) { function initOrThrow(init) { const { cipher, key, binary } = init; const indexed = { 1: [cipher], 2: [key], 3: binary }; return new Headers(Vector.initOrThrow(indexed)); } Headers.initOrThrow = initOrThrow; function readOrThrow(cursor) { const vector = Vector.readOrThrow(cursor); if (vector.value[1].length !== 1) throw new Error(); if (vector.value[2].length !== 1) throw new Error(); if (vector.value[3].length === 0) throw new Error(); const indexed = { 1: [vector.value[1][0].readIntoOrThrow(Cipher)], 2: [vector.value[2][0]], 3: vector.value[3] }; return new Headers(new Vector(vector.bytes, indexed)); } Headers.readOrThrow = readOrThrow; })(Headers || (Headers = {})); export { ContentWithBytes, Headers, HeadersAndContentWithBytes }; //# sourceMappingURL=index.mjs.map