kdbxweb

repository·master·Indexed 19 days ago

https://github.com/keeweb/kdbxweb

A high-performance JavaScript library for reading and writing KeePass v2 (.kdbx) databases in Node.js and browser environments. It supports KDBX3 and KDBX4 formats, conflict-free merging, and secure memory handling of sensitive data via the ProtectedValue class. The library provides utilities for database maintenance, credential management, and binary data handling through KdbxBinaries.

Tokens
11.6K
Snippets
42
Records
58
Agent score
66%

What's inside kdbxweb

  1. Merge Kdbx databases

    master

    KdbxWeb supports conflict-free merging. To merge a remote database into a local one while preserving edit state (useful for P2P or sync scenarios):

    1. Save the local database.
    2. Capture the local edit state using db.getLocalEditState() (this is JSON serializable).
    3. Close the local database.
    4. Reopen the local database and restore the state using db.setLocalEditState(state).
    5. Load the remote database and call db.merge(remoteDb).
    6. Save the merged local database.
    let db = await kdbxweb.Kdbx.load(data, credentials); // load local db
    // work with db
    db.save(); // save local db
    let editStateBeforeSave = db.getLocalEditState(); // save local editing state (serializable to JSON)
    db.close(); // close local db
    
    // reopen it again
    db = kdbxweb.Kdbx.load(data, credentials); 
    db.setLocalEditState(editStateBeforeSave); // assign edit state obtained before save
    
    // work with db
    let remoteDb = await kdbxweb.Kdbx.load(remoteData, credentials);
    db.merge(remoteDb); // merge remote into local
    delete remoteDb; 
    
    let saved = await db.save(); // save local db
  2. Change database credentials

    master

    To update credentials, load the database, use the setPassword or setKeyFile methods on the credentials object, and then call save() on the database instance.

    const db = await kdbxweb.Kdbx.load(data, credentials);
    db.credentials.setPassword(kdbxweb.ProtectedValue.fromString('newPass'));
    const randomKeyFile = await kdbxweb.Credentials.createRandomKeyFile();
    db.credentials.setKeyFile(randomKeyFile);
    await db.save();
  3. Install the Kdbx template for HexFiend

    master

    To use the Kdbx formatting template within HexFiend, you must place the Kdbx.tcl file into the HexFiend Templates directory. You can do this by creating a symbolic link or by copying the file directly.

    Using a symbolic link:

    ln -s format/Kdbx.tcl ~/Library/Application\ Support/com.ridiculousfish.HexFiend/Templates/Kdbx.tcl

    Using copy: Copy Kdbx.tcl to ~/Library/Application Support/com.ridiculousfish.HexFiend/Templates/Kdbx.tcl.

  4. Handle synchronization with local edit state tombstones

    master

    To support successful merging in multi-replica environments (e.g., syncing with a server), Kdbx provides mechanisms to track local edits using JSON-serializable 'tombstones'.

    Workflow for Replicas:

    1. Before Saving: Call getLocalEditState() to get a KdbxEditState object representing current unsynced changes. The replica must save this state along with the database.
    2. On Opening: When the database is opened, the replica must call setLocalEditState(editingState) using the state previously saved.
    3. After Successful Push: Once the local changes are successfully pushed to the upstream source, call removeLocalEditState() to clear the tombstones and discard the previously obtained state.
    // 1. Get state to save with DB
    const state = kdbx.getLocalEditState();
    // ... save state to your storage/DB ...
    
    // 2. On next load
    const loadedKdbx = await Kdbx.load(data, creds);
    loadedKdbx.setLocalEditState(savedState);
    
    // 3. After successful sync
    loadedKdbx.removeLocalEditState();
  5. Import the kdbxweb public API

    master
    The kdbxweb library provides a comprehensive set of tools for working with the KDBX file format, including cryptographic engines, KDBX structure definitions (groups, entries, headers), and utility functions for binary and XML manipulation. You can import the entire public surface from the main entry point.
  6. Implement Argon2 for Kdbx4 support

    master

    Kdbx4 uses Argon2, which is not compiled into the library to allow users to choose their own implementation (e.g., for performance or environment compatibility). To support Kdbx4 files, you must manually provide an implementation via kdbxweb.CryptoEngine.setArgon2Impl.

    kdbxweb.CryptoEngine.setArgon2Impl((password, salt,
        memory, iterations, length, parallelism, type, version
    ) => {
        // your implementation makes hash (Uint8Array, 'length' bytes)
        return Promise.resolve(hash);
    });
  7. Handle Kdbx errors

    master

    Errors thrown by the library are instances of kdbxweb.KdbxError and contain a code property found in kdbxweb.Consts.ErrorCodes.

    try {
        await kdbxweb.Kdbx.load(data, credentials);
    } catch (e) {
        if (e instanceof kdbxweb.KdbxError && e.code === kdbxweb.Consts.ErrorCodes.BadSignature) {
            /* ... */
        }
    }
  8. Perform database maintenance

    master

    Use the following methods to clean up, upgrade, or modify database settings:

    • db.cleanup({ historyRules, customIcons, binaries }): Removes unused data.
    • db.upgrade(): Upgrades the database to the latest version (KDBX4).
    • db.setVersion(3): Downgrades the database to KDBX3.
    • db.setKdf(kdbxweb.Consts.KdfId.Aes): Sets the Key Derivation Function to AES.
    db.cleanup({
        historyRules: true,
        customIcons: true,
        binaries: true
    });
    
    // upgrade the db to latest version (currently KDBX4)
    db.upgrade();
    
    // downgrade to KDBX3
    db.setVersion(3);
    
    // set KDF to AES
    db.setKdf(kdbxweb.Consts.KdfId.Aes);
  9. Use ProtectedValue for sensitive data

    master

    Sensitive values like passwords are handled via kdbxweb.ProtectedValue. These are stored in memory XOR'ed to prevent plain-text exposure in memory dumps.

    Methods:

    • kdbxweb.ProtectedValue.fromString(str): Create from string.
    • kdbxweb.ProtectedValue.fromBinary(data): Create from binary.
    • value.getText(): Retrieve string value.
    • value.getBinary(): Retrieve binary data.
    • value.includes(substring): Check if value contains a substring.
    let valueFromString = kdbxweb.ProtectedValue.fromString('str');
    let textString = valueFromString.getText();
  10. Create a new Kdbx database

    master

    Initialize a new database using kdbxweb.Kdbx.create(credentials, title). You can then create groups and entries within it.

    let newDb = kdbxweb.Kdbx.create(credentials, 'My new db');
    let group = newDb.createGroup(newDb.getDefaultGroup(), 'subgroup');
    let entry = newDb.createEntry(group);
  11. Manage Groups and Entries

    master

    Groups

    • Access: Use db.getDefaultGroup(), db.getGroup(uuid), or traverse via group.groups.
    • Create: db.createGroup(parentGroup, 'name').
    • Delete: db.remove(group).
    • Move: db.move(group, targetGroup, [index]).

    Entries

    • Access: Iterate via group.allEntries() or access via group.entries array.
    • Create: db.createEntry(group).
    • Modify: Use entry.pushHistory() before changes to support merging. Update fields directly (e.g., entry.fgColor).
    • Delete: db.remove(entry).
    • Move: db.move(entry, targetGroup) or db.importEntry(entry, targetGroup, sourceFile) for cross-file moves.
  12. Load a Kdbx database

    master

    You can load a database from an ArrayBuffer or an XML string using kdbxweb.Kdbx.load or kdbxweb.Kdbx.loadXml. Both require a Credentials object.

    let credentials = new kdbxweb.Credentials(kdbxweb.ProtectedValue.fromString('demo'),
        keyFileArrayBuffer, challengeResponseFunction);
    const db1 = await kdbxweb.Kdbx.load(dataAsArrayBuffer, credentials);
    const db2 = await kdbxweb.Kdbx.loadXml(dataAsString, credentials);