pub-keystore v5.1.0
pub-keystore

A simple store for public keys in Node.js.
- Index keys by URI and issuer IDs.
- Listen to key updates.
- Backed by PouchDB, CouchDB 2, SQLite, PostgreSQL or memory.
- Keys can be in any format (or even not keys!).
- Supports access from multiple processes.
- Full set of unit tests.
Example:
var pub_keystore = require('pub-keystore');
var assert = require('assert');
var uri = 'mailto:dave@davedoesdev.com';
var pub_key = 'some key data';
pub_keystore({ db_type: 'pouchdb', db_for_update: true, no_changes: true }, function (err, ks1)
{
pub_keystore({ db_type: 'pouchdb', keep_master_open: true }, function (err, ks2)
{
var the_issuer_id, the_rev;
ks2.on('change', function (id, rev)
{
assert.equal(id, uri);
assert.equal(rev, the_rev);
ks2.get_pub_key_by_issuer_id(the_issuer_id, function (err, pub_key2, uri2, rev2)
{
assert.equal(pub_key2, pub_key);
assert.equal(uri2, uri);
assert.equal(rev2, the_rev);
console.log("done");
});
});
ks1.add_pub_key(uri, pub_key, function (err, issuer_id, rev)
{
the_issuer_id = issuer_id;
the_rev = rev;
ks1.deploy();
});
});
});The API is described here.
Installation
npm install pub-keystoreLicence
Test
grunt testCode Coverage
grunt coveragec8 results are available here.
Coveralls page is here.
Lint
grunt lintCLI
In the cli directory are some command line utilities which call into the API. They do simple things like creating stores and adding and removing public keys. I hope you find them useful but at the very least they should prove good examples of how to call the API.
API
Source: docs.js
Opening a key store
PubKeyStore
Adding and removing keys
Retrieving keys
- PubKeyStore.prototype.get_pub_key_by_uri
- PubKeyStore.prototype.get_pub_key_by_issuer_id
- PubKeyStore.prototype.get_issuer_id
- PubKeyStore.prototype.get_uris
Lifecycle
Replication (PouchDB only)
Events
- PubKeyStore.events.change
- PubKeyStore.events.error
- PubKeyStore.events.replicated
- PubKeyStore.events.replicate_error
module.exports(config, cb)
Opens a public keystore.
Parameters:
{Object} configConfigures the keystore. Valid properties:{String} db_typeThe type of database to use for backing the store. You must supplypouchdb,couchdb,sqlite,pgorin-mem.{String} [db_name](db_type='pouchdb'ordb_type='couchdb') Name of database to use for storing keys. Defaults topub-keys.{Boolean} [db_already_created](db_type='pouchdb'ordb_type='couchdb') If falsey then the database will be created. This is an idempotent operation so it doesn't matter if the database has already been created. However, if you know the database already exists then you can passtrue. Defaults tofalse. If the database doesn't exist and you don't have permission to create it thencbwill receive an error. You must create SQLite and PostgreSQL databases beforehand. For SQLite, use a copy ofsql/pub-keystore.empty.sqlite3.{Boolean} [no_changes]Don't emitchangeevents when a key is changed. Defaults tofalse(i.e. do emitchangeevents).{Boolean} [verbose]Write key changes, warnings and errors toconsole. Defaults tofalse.{Boolean} [no_updates]Don't allowadd_pub_keyto add a key if one already exists for a URI. That is, each URI can only be associated with a public key once and the association cannot be updated. Defaults tofalse.{Boolean} [db_for_update](db_type='pouchdb') PouchDB can only write to a database from one process at a time. If you want to run multiple processes against the same keystore,pub-keystorecan work around this by writing to a master database and then replicating it to multiple reader databases (one for each process). When you're updating keys, passdb_for_update=trueto write to the master database. Make sure youdeployand close the master database after updating it so that your reader processes can open it for replication. Defaults tofalse.{String} [deploy_name](db_type='pouchdb') Name of the replica database to use for the current process (whendb_for_update=false). Make sure you specify a differentdeploy_namefor each process running against the same keystore. Defaults todefault.{String} [db_dir](db_type='pouchdb') Where to write the PouchDB database files. Defaults to a directory namedpouchdb/store/<db_name>in thepub_keystoremodule directory.{Boolean} [no_initial_replicate](db_type='pouchdb') Whether to skip initial replication from the master database. Defaults tofalse. Note that replication will still occur whenever the master database is updated anddeployed.{Boolean} [keep_master_open](db_type='pouchdb') Normally the master database is closed after replicating from it so that it can be updated or replicated from other processes. However, if you want to use master and replica databases from a single process then you'll need to specifykeep_master_open=trueto stop PouchDB getting confused. Defaults tofalse. Normally if only a single process is accessing the keystore then you can just open one instance withdb_for_update=true.{Boolean} [persistent_watch](db_type='pouchdb') Reader processes monitor a shared file to know whendeployhas been called on the master database, usingfs.watch. By default, the watch isn't persistent so it won't keep your process open if nothing else is going on. Passpersistent_watch=trueto make it persistent.{String} [replicate_signal](db_type='pouchdb') Name of a Unix signal (e.g.SIGUSR2) which can be sent to a reader process to force a replication from the master database. Defaults toundefined(no signal will be listened to). Replication normally happens whendeployis called from the writing process orreplicateis called from the reading process.{String} [db_host](db_type='couchdb') URL of the CouchDB server. Defaults tohttp://127.0.0.1.{Integer} [db_port](db_type='couchdb') Port number of the CouchDB server. Defaults to5984.{String} [ca](db_type='couchdb') When connecting using HTTPS, an authority certificate or array of authority certificates to check the remote host against. Defaults toundefined(no checking will be performed).{String} [username](db_type='couchdb') If you need to authenticate to your CouchDB server (e.g. to gain database update rights) then specify the name of the user here. Defaults toundefined(anonymous access). Note that users updating the CouchDB database must have thedb_name-updaterrole, wheredb_nameis the name of the database (see above, the default role required ispub-keys-updater).{String} [password](db_type='couchdb') If you need to authenticate to your CouchDB server (e.g. to gain database update rights) then specify the user's password here. Defaults toundefined(anonymous access).{Integer} [maxSockets](db_type='couchdb') Maximum number of concurrent sockets that can be opened to the CouchDB server. Defaults toInfinity.{Integer} [busy_wait](db_type='sqlite'ordb_type='pg') Number of milliseconds to wait for retrying if another keystore has the database file locked or is performing a transaction. Defaults to 1000.{Integer} [check_interval](db_type='sqlite'ordb_type='pg') Number of milliseconds between checking the database for changes. Defaults to 1000.{String} db_filename(db_type='sqlite') Filename in which to store public keys. You should use a copy ofsqlite/pub-keystore.empty.sqlite3.{Integer} [db_mode](db_type='sqlite') Mode to open the file in. See the sqlite3 documentation.{Object} db(db_type='pg')node-postgresconfiguration.
{Function} cbFunction called with the result of opening the keystore. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull. Note that for PouchDB-backed stores, if the database is already open by another process for update or replication, you will receive an error. It's up to you to retry as appropriate for your application.{PubKeyStore} ksThePubKeyStoreobject. Note that in the case of an error occuring after the store has been open but before a successful changes feed has been established, you may receiveerrandks.
PubKeyStore.prototype.add_pub_key(uri, pub_key, options, cb)
Add a public key to the keystore.
Parameters:
{String} uriA known, permanent identifier for the public key's owner. You can use anything but a URI seems ideal. For example if you know the owner's email address then you could you amailtoURI (e.g.mailto:dave@davedoesdev.com).{String | Object} pub_keyThe public key itself. This can be in any format (e.g. PEM).{Object} [options]Additional options. Valid properties:{Boolean} [allow_update]If you passedno_updates=truewhen opening the keystore, you can override it here by passingtrue, which allows this call to update an existing public key.
{Function} [cb]Function to call once the key has been added. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull.{String} issuer_idA unique, hex-encoded, random string which you can use as an alternative when retrieving the public key. This is useful if you want to give out an identifier for the key without revealing its owner. Note that every time you add a key, a newissuer_idwill be generated. If a key already exists for theurithen it will be overwritten.{String} revA revision string for the key. Like theissuer_id, this will change every time a key is added. Unlike theissuer_id, it is sent withchangeevents so you if you're caching keys then you can tell whether the cached version is up-to-date.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.remove_pub_key(uri, cb)
Remove a public key from the keystore.
Parameters:
{String} uriThe permanent identifier you gave to the key when adding it usingadd_pub_key.{Function} [cb]Function to call once the key has been removed. It will receive the following argument:{Object} errIf an error occurred then details of the error, otherwisenull. A non-existent key is not treated as an error.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.get_pub_key_by_uri(uri, cb)
Retrieve a public key using its permanent identifier (URI).
Parameters:
{String} uriThe permanent identifier you gave to the key when adding it usingadd_pub_key.{Function} cbFunction to call with the result. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull. A non-existent key is not treated as an error.{String|Object} pub_keyThe public key for theuri, ornullif it wasn't found.{String} issuer_idThe current unique, random string you can use to retrieve the key usingget_pub_key_by_issuer_id.{String} revThe current revision string for the public key.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.get_pub_key_by_issuer_id(issuer_id, cb)
Retrieve a public key using its unique, random identifier.
Parameters:
{String} issuer_idThe unique identifier for the key.{Function} cbFunction to call with the result. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull. A non-existent key is not treated as an error.{String|Object} pub_keyThe public key for theissuer_id, ornullif it wasn't found.{String} uriThe permanent identifier you gave to the key when adding it usingadd_pub_key.{String} revThe current revision string for the public key.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.get_issuer_id(uri, cb)
Get a unique, random identifier for a public key.
Parameters:
{String} uriThe permanent identifier you gave to the key when adding it usingadd_pub_key.{Function} cbFunction to call with the result. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull. A non-existent key is not treated as an error.{String} issuer_idThe current unique, random string you can use to retrieve the key usingget_pub_key_by_issuer_id, ornullif it wasn't found.{String} revThe current revision string for the public key.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.get_uris(cb)
Get a list of all of the public key URIs in the store.
Parameters:
{Function} cbFunction to call with the result. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull.{Array} urisURIs of all the public keys in the store.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.close(cb)
Close the store and its backing database.
Parameters:
{Function} [cb]Function to call once the database has been closed. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.create(cb)
Create the store's backing database.
Unless you pass db_already_created=true when opening the keystore, this method is automatically called for you when the store is opened. It is an idempotent operation so it doesn't matter if you call it twice.
For SQLite- and PostgreSQL-backed databases, this is a no-op: you must create the database beforehand. For in-memory databases, this is also a no-op.
Parameters:
{Function} [cb]Function to call once the database has been created. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.destroy(cb)
Close the store and destroy its backing database. This will delete all public keys!
For SQLite- and PostgreSQL-backed databases, this deletes the keys but doesn't destroy the database.
Parameters:
{Function} [cb]Function to call once the database has been destroyed. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.deploy(cb)
(PouchDB) Notify reader processes to replicate from the master database. You should call this when you've opened the keystore with
db_for_update=true, performed some updates and want other processes reading from the store to receive the updates. Internally it usestouchandfs.watchon a shared file.
For CouchDB-, SQLite-, PostgreSQL- and memory-backed keystores, this is a no-op.
Parameters:
{Function} [cb]Function to call once the shared file has beentouched. Note this will be before reader processes finish replicating. It will receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull.
Go: TOC | PubKeyStore.prototype
PubKeyStore.prototype.replicate(opts, cb)
(PouchDB) Force replication from the master database. Usually you shouldn't need to call this because reader processes (where the keystore is opened without
db_for_update=true) will replicate when the keystore is opened and when they detect that a writer process has calleddeploy.
For CouchDB-, SQLite-, PostgreSQL- and memory-backed keystores, this is a no-op.
Parameters:
{Object} optsReplication options. Valid properties:{Boolean} no_retryIf replication fails (typically because the master database is open in another process also trying to replicate) then it is automatically retried after a random delay of between 1 and 2 seconds. Setno_retrytotrueto disable this behaviour. Defaults tofalse.
{Functon} [cb]Function to call once replication has completed successfully (or failed if you setopts.no_retry=trueand an error occurred). Alternatively you can listen for thereplicatedevent which is emitted on successful replication (for consistency, CouchDB-backed stores will raise this too, after the no-op).cbwill receive the following arguments:{Object} errIf an error occurred then details of the error, otherwisenull.
Go: TOC | PubKeyStore.prototype
PubKeyStore.events.change(uri, rev, deleted)
changeevent
Emitted when a public key is updated or removed from the keystore.
Parameters:
{String} uriThe permanent identifier for the key.{String} revThe new revision string for the key.{Boolean} deletedWhether the key has been removed from the store.
Go: TOC | PubKeyStore.events
PubKeyStore.events.error(err)
errorevent
Emmited when an error occurs in the changes feed from the database. This may mean you receive no more change events.
Parameters:
{Object} errDetails of the error.
Go: TOC | PubKeyStore.events
PubKeyStore.events.replicated(close_master)
replicatedevent
Emitted when a successful replication from the master database completes (PouchDB-backed keystores). CouchDB-, SQLite-, PostgreSQL- and memory-backed stores emit this too for consistency, after replicate is called.
Parameters:
{Function} close_masterFunction you can call to close the master database if you setconfig.keep_master_open=truewhen opening the keystore. This lets you control when to close the master database yourself. If you didn't setconfig.keep_master_open=truethenclose_masteris a no-op.close_mastertakes the following parameters:{Function} cb(err)This will be called after the master database is closed (or after the no-op).
Go: TOC | PubKeyStore.events
PubKeyStore.events.replicate_error(err)
replicate_errorevent
Emitted when replication from the master database fails (PouchDB-backed keystores only). This is emitted even when replication retry is enabled (i.e. if you didn't set no_retry=true when opening the store).
Parameters:
{Object} errDetails of the error.
Go: TOC | PubKeyStore.events
—generated by apidox—
2 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago