Buttercup Core


Buttercup core library

A NodeJS password vault.

Buttercup npm npm version node min version security encryption Join the chat at https://gitter.im/buttercup-pw/buttercup-core

Build Status

NPM NPM

Please be aware that breaking changes will occur during 0.* (alpha) development. Until 1.0 is released, assume that every minor version contains breaking changes to encryption, structure and API.

About

Buttercup is a password manager written in JavaScript for NodeJS (and the browser!). It's based around Archives that contain Groups and Entrys. Together, in a nested structure, these items act as a secure store for a user's credentials (much like standard managers these days). Entries allow you to store a credential's username and password, along with other miscellaneous properties (meta) and invisible functional info (attributes).

Buttercup archives sit in memory as an Object instance that is built from delta-style commands that modify the structure. As changes are made to the archive, new delta commands are added to the history and saved to the archive's Datasource. Archives are compressed and encrypted before being saved.

Features

The core of the system, this Buttercup Core, boasts a few awesome features:

  • Deltas for storing archive history
  • Conflict resolution and archive merging
  • 256bit AES-CBC encryption
  • SHA-256 keys using PBKDF2 derivation
  • SHA-256 HMAC authentication
  • GZip text compression

This library also supports a variety of datasources for loading from and saving to:

You may want to read the API documentation and changelog. Please read our guide to contributing before creating any issues or pull requests.

Buttercup suite

This core library fuels the processing for several other libraries, such as the desktop application, core library for use in browsers, server for hosting archives and command-line application.

Usage

Buttercup can easily be imported and used in NodeJS applications from version 4.x and upwards:

const Buttercup = require("buttercup"); // buttercup-core is "buttercup" on npm

Creating content

Archives are easily created by making a new instance:

const Archive = Buttercup.Archive;

let myArchive = new Archive();

Groups can be created within other groups or archives:

let websitesGroup = myArchive.createGroup("Websites");

let bankingGroup = websitesGroup.createGroup("Banking");

Entries can be created within groups, which hold authentication information:

let worldBank = bankingGroup.createEntry("World bank");

worldBank
    .setProperty("username", "johnSmith87")
    .setProperty("password", "3mX*7m, #jP0")
    .setMeta("URL", "www.world-bank.com");

Entries can be moved to other groups, and groups to other groups or archives:

worldBank.moveToGroup(websitesGroup);

bankingGroup.moveTo(myArchive); // move up to the root level

Deleting content

Groups and entries can easily be deleted:

myEntry.delete(); // `myEntry` reference no longer valid

myGroup.delete(); // `myGroup` reference no longer valid

It's important to note that just because a group or entry is deleted, does not mean that its corresponding information has. Historical commands are still stored in the archive dataset until they are flattened (after several thousand following commands).

Saving and loading

Archives can be saved with datasources:

const { FileDatasource, createCredentials } = Buttercup;

let ds = new FileDatasource("~/myArchive.bcup");
ds.save(myArchive, createCredentials.fromPassword("myPa55word")).then(function() {
    console.log("Saved!");
});

ds.load(createCredentials.fromPassword("myPa55word"))
    .then(function(archive) {
        // loaded `archive`
    })
    .catch(function(err) {
        console.error("Failed: " + err.message);
    });

Archives can be managed more easily using a Workspace. Workspaces are designed to handle a primary archive and potentially several shared archives, each with their own master password and datasource. When integrating with Buttercup server, workspaces allow you to handle multiple shared archives where groups can be handled by multiple users.

const { Workspace, createCredentials } = Buttercup;

let workspace = new Workspace();
workspace
    .setPrimaryArchive(myArchive, myDatasource, createCredentials.fromPassword("master password"))
    .addSharedArchive(sharedArchive1, sharedDS1, createCredentials.fromPassword("shared pass"), /* saveable */ true);

workspace
    .save()
    .then(function() {
        console.log("Saved all archives!");
    });

Workspaces also allow you to detect conflicts before saving so you can perform merges on the local content:

workspace
    .localDiffersFromRemote()
    .then(function(differs) {
        if (differs) {
            return workspace.mergeSaveablesFromRemote();
        }
    })
    .then(function() {
        // all up to date
        return workspace.save();
    });

Searching for things

You can search within archives for certain entries or groups:

archive
    .findEntriesByProperty("title", /^Home-[a-z]+$/i)
    .forEach(function(entry) {
        // Do something with entry
    });

archive
    .findGroupsByTitle("banking")
    .forEach(function(group) {});

group.findEntriesByMeta("postcode", /^0\d{4}$/);

Importing

You can import from other password archive formats, such as KeePass. Checkout the Buttercup Importer project.

Performance and web support

Some things in Buttercup are best run purely on Node, such has password-based key derivation. When preparing this for the web (such as with Webpack or Browserify), things can move very slowly. There are implementations for functions, such as PBKDF2, that exist for web use that are many times faster than the output of such build utilities.

You can override PBKDF2 by doing the following (documented on iocane):

var Buttercup = require("buttercup");
Buttercup.vendor.iocane.components.setPBKDF2(newPBKDF2Function);
// Where 'newPBKDF2Function' is a function that returns a Promise with the hash in a Buffer

Buttercup uses webdav-fs under the hood for support of several storage providers, and this in turn uses node-fetch for requests. node-fetch does not work in every environment (such as React-Native) and needs to be switched for a native alterative, like global.fetch. Webdav-fs supports this via the setFetchMethod, which can be called in Buttercup like so:

var Buttercup = require("buttercup");
Buttercup.vendor.webdavFS.setFetchMethod(global.fetch);
// Where `global.fetch` is a fetch-API supporting method

Attributes

Entries and groups have attributes, describing how they should be treated by the various interfaces that interact with the archive. Attributes are not visible to the users and can contain a variety of different properties.

For instance, you could get the role of a group like so:

let groupRole = group.getAttribute(ManagedGroup.Attributes.Role);

Entry types and facades are documented separately.

Debugging

Buttercup supports the DEBUG environment variable. You can debug an application using Buttercup like so:

DEBUG=buttercupcore:* ./app

This also works when running the tests:

DEBUG=buttercupcore:* npm test

The iocane submodule also supports DEBUG:

DEBUG=buttercupcore:*,iocane ./app
# or
DEBUG=buttercupcore:*,iocane npm test

Related Repositories

buttercup-desktop

buttercup-desktop

:key: Javascript Password Vault - Multi-Platform Desktop Application ...

EventCentric.Core

EventCentric.Core

Event Sourcing and CQRS in PHP ...

bjorn

bjorn

Paths go in, coolness comes out. ...

domain

domain

Adds interfaces and base classes for DomainEvents, Aggregates, Snapshotting (the ...


Top Contributors

perry-mitchell Jameskmonger sallar

Releases

-   v0.25.0 zip tar
-   v0.24.0 zip tar
-   v0.23.0 zip tar
-   v0.22.0 zip tar
-   v0.21.0 zip tar
-   v0.20.1 zip tar
-   v0.20.0 zip tar
-   v0.19.0 zip tar
-   v0.18.0 zip tar
-   v0.17.0 zip tar
-   v0.16.0 zip tar
-   v0.15.1 zip tar
-   v0.15.0 zip tar
-   v0.13.0 zip tar
-   v0.12.2 zip tar
-   v0.12.1 zip tar
-   v0.12.0 zip tar
-   v0.11.4 zip tar
-   v0.11.3 zip tar
-   v0.9.0 zip tar
-   v0.6.0 zip tar
-   v0.5.1 zip tar
-   v0.5.0 zip tar
-   v0.4.1-a zip tar
-   v0.4.0-a zip tar
-   v0.3.0-a zip tar
-   v.0.2.2-a zip tar
-   v0.2.1-a zip tar
-   0.14.0 zip tar