Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
hoodie-plugin-store-crypto
Advanced tools
End-to-end crypto plugin for the Hoodie client store.
This Hoodie plugin adds methods, to add, read and update encrypted documents in your users store, while still being able to add, read and update unencrypted documents.
It does this by adding an object to your Hoodie-client, with similar methods to the client's store. Those methods encrypt and decrypt objects, while using the corresponding methods from Hoodie to save them.
There is no server side to this plugin!
Everything of a doc will be encrypted, except _id
, _rev
, _deleted
, _attachments
, _conflicts
and the hoodie
object!
hoodie.store.add({foo: 'bar'})
.then(function (obj) {console.log(obj)})
hoodie.cryptoStore.setPassword('secret') // unlock
.then(function (salt) {
hoodie.cryptoStore.add({foo: 'bar'}) // adds the object encrypted
.then(function (obj) {console.log(obj)}) // returns it unencrypted!
})
This project heavily uses code and is inspired by @calvinmetcalf's crypto-pouch and Hoodie's hoodie-store-client.
A huge thank you to those projects and their maintainers.
There are 2 ways to use this plugin in your app:
This will add the cryptoStore to your /hoodie/client.js
if you use the hoodie
package.
First, install the plugin as dependency of your Hoodie app:
npm install --save hoodie-plugin-store-crypto
Then add it to the hoodie.plugins
array in your app’s package.json
file.
{
"name": "your-hoodie-app",
...
"hoodie": {
"plugins": [
"hoodie-plugin-store-crypto"
]
}
}
You can now start your app with npm start
. There should now be an cryptoStore
property on your client hoodie
instance. You can access it with
hoodie.cryptoStore
.
If you are using a client bundler (e.g. Browserify or Webpack), then you can import it manually.
First, install the plugin as dev-dependency of your Hoodie app:
npm install --save-dev hoodie-plugin-store-crypto
Then require it and set it up:
var Hoodie = require('@hoodie/client')
var PouchDB = require('pouchdb')
var cryptoStore = require('hoodie-plugin-store-crypto')
var hoodie = new Hoodie({ // create an instance of the hoodie-client
url: '',
PouchDB: PouchDB
})
cryptoStore(hoodie) // sets up hoodie.cryptoStore
You only need to do it this way, if you directly require/import the @hoodie/client
!
If you get the client with <script src="/hoodie/client.js"></script>
, then the first way is recommended.
To use the cryptoStore you need to set a password for encryption. This can be your users password to your app, or a special password, which they will enter or you generate.
There are 4 use-cases you must implement:
The first use of the cryptoStore. This is usually in your sign up function, but can also be done if you newly added this plugin.
cryptoStore.setPassword(password)
is used to set the
encryption password. It will resolve with a salt
. A salt is a second part of a password.
cryptoStore.setPassword(password)
will save the generated salt in _design/cryptoStore/salt
, and
use it.
Example:
function signUp (username, password, cryptoPassword) {
return hoodie.account.signUp({username: username, password: password})
.then(function (accountProperties) {
return hoodie.cryptoStore.setPassword(cryptoPassword)
.then(function (salt) {
// now do what you do after you did sign up a user.
})
})
}
Every time your user signs in you also need to unlock the cryptoStore.
cryptoStore.setPassword(password)
is also used for unlocking.
After sign in you must wait for the store to sync and then unlock the cryptoStore.
You must wait for the sync to finish, because the _design/cryptoStore/salt
and
hoodiePluginCryptoStore/salt
objects must be updated to the latest version to unlock the
cryptoStore! If the salt doc is missing, a new one will be created! Resulting in a new encryption key!
Example:
function signIn (username, password, cryptoPassword) {
return hoodie.account.signIn({username: username, password: password})
.then(function (accountProperties) {
return hoodie.store.sync([
'_design/cryptoStore/salt',
'hoodiePluginCryptoStore/salt'
]) // wait for syncing to finish!
.then(function () {
return accountProperties
})
})
.then(function (accountProperties) {
return hoodie.cryptoStore.setPassword(cryptoPassword)
.then(function (salt) {
// now do what you do after sign in.
})
})
}
The cryptoStore
listen automatically to hoodie.account.on('signout')
events and locks itself. You don't need to add any setup for it.
The cryptoStore.lock()
method is there, so that you can add a lock after a timeout functionality or lock the store in a save way when closing an tab.
window.addEventListener('beforeunload', function (event) {
// do your cleanup
hoodie.cryptoStore.lock() // lock the cryptoStore in an cryptographic save way.
})
This plugin doesn't save your users password! That results in you having to unlock the cryptoStore on every instance/tap of your web-app!
Here you also must wait for syncing to finish! But only if your user is online.
Example:
function unlock (cryptoPassword) {
return hoodie.connectionStatus.check() // check if your app is online
.then(function () {
if (hoodie.connectionStatus.ok) { // if your app is online: sync your users store
return hoodie.store.sync()
}
})
.then(function () {
return hoodie.cryptoStore.setPassword(cryptoPassword) // then unlock
})
}
You can change the password and salt used for encryption with cryptoStore.changePassword(oldPassword, newPassword)
.
This method also updates all documents, that are encrypted with the old password!
It is recommended to sync before the password change! To update all documents.
Example:
function changePassword (oldPassword, newPassword) {
return hoodie.connectionStatus.check() // check if your app is online
.then(function () {
if (hoodie.connectionStatus.ok) { // if your app is online: sync your users store
return hoodie.store.sync()
}
})
.then(function () {
return hoodie.cryptoStore.changePassword(oldPassword, newPassword)
})
.then(function (result) {
console.log(result.notUpdated) // array of ids of all docs that weren't updated
})
}
This plugin uses the sha256
and pbkdf2
algorithm for generating a key from your password. The key is a 32 char Hash. And for encryption and decryption of your docs the AES-GCM
algorithm is used.
Hoodie, CouchDB and PouchDB need _id
, _rev
, _deleted
, _attachments
and _conflicts
to function. They and the content of the hoodie
object, are not encrypted!
Everything else is run through JSON.stringify
and encrypted.
Please be aware, that the _id
of a doc is not encrypted! Don't store important or personal information in the _id
!
var pbkdf2 = require('native-crypto/pbkdf2')
var randomBytes = require('randombytes')
function deriveKey (password) {
return hoodie.store.find('_design/cryptoStore/salt')
.then(function (doc) {
var digest = 'sha256'
var iterations = 100000
var salt = doc.salt != null && typeof doc.salt === 'string' && doc.salt.length === 32
? doc.salt
: randomBytes(16).toString('hex')
return pbkdf2(password, Buffer.from(salt, 'hex'), iterations, 256 / 8, digest)
.then(function (key) {
return {
key: key,
salt: salt
}
})
})
}
var nativeCrypto = require('native-crypto')
var randomBytes = require('randombytes')
var ignore = [
'_id',
'_rev',
'_deleted',
'_attachments',
'_conflicts',
'hoodie'
]
function encryptDoc (key, doc) {
var nonce = randomBytes(12)
var outDoc = {
nonce: nonce.toString('hex')
}
ignore.forEach(function (key) {
outDoc[key] = doc[key]
delete doc[key]
})
var data = JSON.stringify(doc)
return nativeCrypto.encrypt(key, nonce, data, Buffer.from(outDoc._id))
.then(function (response) {
outDoc.tag = response.slice(-16).toString('hex')
outDoc.data = response.slice(0, -16).toString('hex')
return outDoc
})
}
var nativeCrypto = require('native-crypto')
var ignore = [
'_id',
'_rev',
'_deleted',
'_attachments',
'_conflicts',
'hoodie'
]
function decryptDoc (key, doc) {
var data = Buffer.from(doc.data, 'hex')
var tag = Buffer.from(doc.tag, 'hex')
var encryptedData = Buffer.concat([data, tag])
var nonce = Buffer.from(doc.nonce, 'hex')
var aad = Buffer.from(doc._id)
return nativeCrypto.decrypt(key, nonce, encryptedData, aad)
.then(function (outData) {
var out = JSON.parse(outData)
ignore.forEach(function (key) {
var ignoreValue = doc[key]
if (ignoreValue !== undefined) {
out[key] = ignoreValue
}
})
return out
})
}
cryptoStore(hoodie)
Argument | Type | Description | Required |
---|---|---|---|
hoodie | Object | Hoodie client instance | Yes |
Returns undefined
Only required if you setup your hoodie-client youself!
Example
var Hoodie = require('@hoodie/client')
var PouchDB = require('pouchdb')
var cryptoStore = require('hoodie-plugin-store-crypto')
var hoodie = new Hoodie({ // create an instance of the hoodie-client
url: '',
PouchDB: PouchDB
})
cryptoStore(hoodie) // sets up hoodie.cryptoStore
hoodie.cryptoStore.setPassword('test')
.then(function (salt) {
console.log('done')
})
cryptoStore.setPassword(password)
Argument | Type | Description | Required |
---|---|---|---|
password | String | A password for encrypting the objects | Yes |
Resolves with a salt
. A salt is a string that will be used with the password together for the encryption.
It is saved with the id
_design/cryptoStore/salt
. It also tests hoodiePluginCryptoStore/salt
for the salt.
It doesn't reject!
Example
function signUp (accountProperties, encryptionPW) {
hoodie.account.signUp(accountProperties)
.then(function () {
if (encryptionPW == null) { // Use a separate password for encryption or the same
encryptionPW = accountProperties.password
}
return hoodie.cryptoStore.setPassword(encryptionPW)
.then(function (salt) { // Salt is saved for you under `_design/cryptoStore/salt`
console.log('Encryption is enabled!')
})
})
}
cryptoStore.setPassword(password, salt)
Argument | Type | Description | Required |
---|---|---|---|
password | String | A password for encrypting the objects | Yes |
salt | String | A string generated by setPassword(password) , to add another protection lair, as a second password. If this is missing, a salt will be generated. Which will result in a different encryption! | Yes |
Resolves with a salt
. A salt is a string that will be used with the password together for the encryption.
It is saved with the id
_design/cryptoStore/salt
.
It doesn't reject!
Example
function signIn (accountProperties, encryptionPW) {
hoodie.account.signIn(accountProperties)
.then(function () {
return hoodie.store.find('cryptoSalt')
})
.then(function (saltObj) {
if (encryptionPW == null) { // Use a separate password for encryption or the same
encryptionPW = accountProperties.password
}
return hoodie.cryptoStore.setPassword(encryptionPW, saltObj.salt)
})
.then(function (salt) {
console.log('you did sign in!')
})
}
cryptoStore.changePassword(oldPassword, newPassword)
Argument | Type | Description | Required |
---|---|---|---|
oldPassword | String | The old password, that was used up until now | Yes |
newPassword | String | New password, with which the docs will be encrypted | Yes |
Resolves with an object with the new salt
and an array (notUpdated
) with the ids of not updated docs.
It will update all with oldPassword
encrypted documents. And encrypt them with with the help of
the newPassword
. It also updates the salt
in _design/cryptoStore/salt
.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.changePassword('my-old-password', 'secret').then(function (report) {
console.log('all documents are updated!')
console.log(report.salt) // the new salt
console.log(report.notUpdated) // array with all ids of encrypted docs that hasn't been updated
}).catch(function (error) {
console.error(error)
})
cryptoStore.lock()
This locks the store and every method fails until a new password is set. It also overwrites the internal key's memory in a in an cryptographic save way (10 times).
Resolves with a Boolean. true
if the store is now locked, false
if the store was already locked.
The cryptoStore
listen automatically to hoodie.account.on('signout')
events and locks itself.
cryptoStore.add(properties)
Argument | Type | Description | Required |
---|---|---|---|
properties | Object | properties of document | Yes |
properties._id | String | If set, the document will be stored at given id | No |
Resolves with properties
unencrypted and adds id
(unless provided). And adds a hoodie
property with createdAt
and updatedAt
properties. It will be encrypted.
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-26T18:38:32.920Z"
}
}
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.add({foo: 'bar'}).then(function (doc) {
console.log(doc.foo) // bar
}).catch(function (error) {
console.error(error)
})
cryptoStore.add([properties])
Argument | Type | Description | Required |
---|---|---|---|
arrayOfProperties | Array | Array of properties , see cryptoStore.add(properties) | Yes |
Resolves with an array of properties
unencrypted in the arrayOfProperties
and adds _id
(unless provided). And adds a hoodie
property with createdAt
and updatedAt
properties. It will be encrypted.
[
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-26T18:38:32.920Z"
}
}
]
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.add([{foo: 'bar'}, {bar: 'baz'}]).then(function (docs) {
console.log(docs.length) // 2
}).catch(function (error) {
console.error(error)
})
cryptoStore.find(id)
Argument | Type | Description | Required |
---|---|---|---|
id | String | Unique id of the document | Yes |
Resolves with properties
unencrypted. Works on encrypted and unencrypted documents.
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-26T18:38:32.920Z"
}
}
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.find('12345678-1234-1234-1234-123456789ABC').then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.find(doc)
Argument | Type | Description | Required |
---|---|---|---|
doc | Object | Document with _id property | Yes |
Resolves with properties
unencrypted. Works on encrypted and unencrypted documents.
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-26T18:38:32.920Z"
}
}
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.find(doc).then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.find([doc])
Argument | Type | Description | Required |
---|---|---|---|
idsOrDocs | Array | Array of id (String) or doc (Object) items | Yes |
Resolves with array of properties
unencrypted. Works on encrypted and unencrypted documents.
[
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-26T18:38:32.920Z"
}
}
]
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.find([
doc,
"12345678-1234-1234-1234-123456789ABC"
]).then(function (docs) {
console.log(docs.length) // 2
}).catch(function (error) {
console.error(error)
})
cryptoStore.findOrAdd(id, doc)
Argument | Type | Description | Required |
---|---|---|---|
id | String | Unique id of the document | Yes |
doc | Object | Document that will be saved if no document with the id exists | Yes |
Resolves with properties
unencrypted. Works on encrypted and unencrypted documents. If doc is added, it will be encrypted and a hoodie
property with createdAt
and updatedAt
properties added.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.findOrAdd('12345678-1234-1234-1234-123456789ABC', doc).then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.findOrAdd(doc)
Argument | Type | Description | Required |
---|---|---|---|
doc | Object | Document with _id property | Yes |
Resolves with properties
unencrypted. Works on encrypted and unencrypted documents. If doc is added, it will be encrypted and a hoodie
property with createdAt
and updatedAt
properties added.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.findOrAdd(doc).then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.findOrAdd(idsOrDocs)
Argument | Type | Description | Required |
---|---|---|---|
idsOrDocs | Array | Array of documents with _id property or ids | Yes |
Resolves with array of properties
unencrypted. Works on encrypted and unencrypted documents. If a doc is added, it will be encrypted and a hoodie
property with createdAt
and updatedAt
properties added.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.findOrAdd([
doc,
'12345678-1234-1234-1234-123456789ABC'
]).then(function (docs) {
console.log(docs.length) // 2
}).catch(function (error) {
console.error(error)
})
cryptoStore.findAll(filterFunction)
Argument | Type | Description | Required |
---|---|---|---|
filterFunction | Function | Function that will be called for every doc with doc , index and arrayOfAllDocs . And returns true if doc should be returned, false if not. | No |
Resolves with array of properties
unencrypted. Works on encrypted and unencrypted documents.
[
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-26T18:38:32.920Z"
}
}
]
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
function filter (doc, index, allDocs) {
return index % 2 === 0
}
hoodie.cryptoStore.findAll(filter).then(function (docs) {
console.log(docs.length)
}).catch(function (error) {
console.error(error)
})
cryptoStore.update(id, changedProperties)
Argument | Type | Description | Required |
---|---|---|---|
id | String | Unique id of the document | Yes |
changedProperties | Object | Properties that should be changed | Yes |
Resolves with updated properties
unencrypted. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.update('12345678-1234-1234-1234-123456789ABC', {foo: 'bar'}).then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.update(id, updateFunction)
Argument | Type | Description | Required |
---|---|---|---|
id | String | Unique id of the document | Yes |
updateFunction | Function | Function that get the document passed and changes the document. | Yes |
Resolves with updated properties
unencrypted. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
function updater (doc) {
doc.foo = 'bar'
}
hoodie.cryptoStore.update('12345678-1234-1234-1234-123456789ABC', updater).then(function (doc) {
console.log(doc.foo) // bar
}).catch(function (error) {
console.error(error)
})
cryptoStore.update(doc)
Argument | Type | Description | Required |
---|---|---|---|
doc | Object | Properties that should be changed with a _id property | Yes |
Resolves with updated properties
unencrypted. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.update({
_id: '12345678-1234-1234-1234-123456789ABC',
foo: 'bar'
}).then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.update(arrayOfDocs)
Argument | Type | Description | Required |
---|---|---|---|
arrayOfDocs | Array | Array properties that should be changed with a _id property | Yes |
Resolves with an array of updated properties
unencrypted. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.update([
{
_id: '12345678-1234-1234-1234-123456789ABC',
foo: 'bar'
},
otherDoc
]).then(function (docs) {
console.log(docs.length) // 2
}).catch(function (error) {
console.error(error)
})
cryptoStore.updateOrAdd(id, doc)
Argument | Type | Description | Required |
---|---|---|---|
id | String | Unique id of the document | Yes |
doc | Object | Properties that should be changed or added if doc doesn't exist | Yes |
Resolves with updated properties
unencrypted. Updates existing documents and adds nonexistent docs. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted. If the doc is added, it will be encrypted and a hoodie
property with createdAt
and updatedAt
properties added.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.updateOrAdd('12345678-1234-1234-1234-123456789ABC', {foo: 'bar'}).then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.updateOrAdd(doc)
Argument | Type | Description | Required |
---|---|---|---|
doc | Object | Properties that should be changed or added with a _id property | Yes |
Resolves with updated properties
unencrypted. Updates existing documents and adds nonexistent docs. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted. If the doc is added, it will be encrypted and a hoodie
property with createdAt
and updatedAt
properties added.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.updateOrAdd({
_id: '12345678-1234-1234-1234-123456789ABC',
foo: 'bar'
}).then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.updateOrAdd(arrayOfDocs)
Argument | Type | Description | Required |
---|---|---|---|
arrayOfDocs | Array | Array properties that should be changed or added with a _id property | Yes |
Resolves with an array of updated properties
unencrypted. Updates existing documents and adds nonexistent docs. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted. If the doc is added, it will be encrypted and a hoodie
property with createdAt
and updatedAt
properties added.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.updateOrAdd([
{
_id: '12345678-1234-1234-1234-123456789ABC',
foo: 'bar'
},
otherDoc
]).then(function (docs) {
console.log(docs.length) // 2
}).catch(function (error) {
console.error(error)
})
cryptoStore.updateAll(changedProperties)
Argument | Type | Description | Required |
---|---|---|---|
changedProperties | Object | Properties that should be changed by all documents | Yes |
Resolves with updated properties
unencrypted. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted.
This updates and encrypts all documents with its idPrefix!
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
// This updates and encrypts all documents in the users store!
hoodie.cryptoStore.updateAll({foo: 'bar'}).then(function (docs) {
console.log(docs) // all docs!
}).catch(function (error) {
console.error(error)
})
// This updates and encrypts all documents that have an _id that starts with 'foo/'!
hoodie.cryptoStore.withIdPrefix('foo/').updateAll({foo: 'bar'}).then(function (docs) {
console.log(docs) // all docs whose _id starts with 'foo/'!
}).catch(function (error) {
console.error(error)
})
cryptoStore.updateAll(updateFunction)
Argument | Type | Description | Required |
---|---|---|---|
updateFunction | Function | Function that get the document passed and changes the document. | Yes |
Resolves with updated properties
unencrypted. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted.
This updates and encrypts all documents with its idPrefix!
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
// This updates and encrypts all documents in the users store!
hoodie.cryptoStore.updateAll(function (doc) {
doc.foo = 'bar'
}).then(function (docs) {
console.log(docs) // all docs!
}).catch(function (error) {
console.error(error)
})
// This updates and encrypts all documents that have an _id that starts with 'foo/'!
hoodie.cryptoStore.withIdPrefix('foo/').updateAll(function (doc) {
doc.foo = 'bar'
}).then(function (docs) {
console.log(docs) // all docs whose _id starts with 'foo/'!
}).catch(function (error) {
console.error(error)
})
cryptoStore.remove(id)
Argument | Type | Description | Required |
---|---|---|---|
id | String | Unique id of the document | Yes |
Resolves with properties
unencrypted. Works on encrypted and unencrypted documents. It set the document to deleted. If the document was unencrypted it will be encrypted. It adds deletedAt
to the hoodie
property.
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"_deleted": true,
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-30T00:05:46.976Z",
"deletedAt": "2018-05-30T00:05:46.976Z"
}
}
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.remove('12345678-1234-1234-1234-123456789ABC').then(function (doc) {
console.log(doc)
}).catch(function (error) {
console.error(error)
})
cryptoStore.remove(doc)
Argument | Type | Description | Required |
---|---|---|---|
doc | Object | Properties that should be changed with a _id property | Yes |
Resolves with properties
unencrypted. Works on encrypted and unencrypted documents. It set the document to deleted and updates properties
. If the document was unencrypted it will be encrypted. It adds deletedAt
to the hoodie
property.
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"_deleted": true,
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-30T00:05:46.976Z",
"deletedAt": "2018-05-30T00:05:46.976Z"
}
}
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.remove({
_id: '12345678-1234-1234-1234-123456789ABC',
foo: 'bar'
}).then(function (doc) {
console.log(doc.foo) // bar
}).catch(function (error) {
console.error(error)
})
cryptoStore.remove(idsOrDocs)
Argument | Type | Description | Required |
---|---|---|---|
idsOrDocs | Array | Properties that should be changed with a _id property or ids | Yes |
Resolves with properties
unencrypted. Works on encrypted and unencrypted documents. It set the document to deleted and updates properties
. If the document was unencrypted it will be encrypted. It adds deletedAt
to the hoodie
property.
[
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"_deleted": true,
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-30T00:05:46.976Z",
"deletedAt": "2018-05-30T00:05:46.976Z"
}
}
]
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
hoodie.cryptoStore.remove([
doc,
'12345678-1234-1234-1234-123456789ABC'
]).then(function (docs) {
console.log(docs.length) // 2
}).catch(function (error) {
console.error(error)
})
cryptoStore.removeAll(updateFunction)
Argument | Type | Description | Required |
---|---|---|---|
filterFunction | Function | Function that will be called for every doc with doc , index and arrayOfAllDocs . And returns true if doc should be returned, false if not. | No |
Resolves with updated properties
unencrypted. Works on encrypted and unencrypted documents. If the document was unencrypted it will be encrypted.
[
{
"_id": "12345678-1234-1234-1234-123456789ABC",
"_deleted": true,
"foo": "bar",
"hoodie": {
"createdAt": "2018-05-26T18:38:32.920Z",
"updatedAt": "2018-05-30T00:05:46.976Z",
"deletedAt": "2018-05-30T00:05:46.976Z"
}
}
]
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
function filter (doc, index, allDocs) {
return index % 2 === 0
}
hoodie.cryptoStore.removeAll(filter).then(function (docs) {
console.log(docs.length)
}).catch(function (error) {
console.error(error)
})
cryptoStore.on(eventName, handler)
Argument | Type | Description | Required |
---|---|---|---|
eventName | String | Event type. One of add , update , remove or change . | Yes |
handler | Function | Event Handler, that will be called every time that event emits. | Yes |
Returns the cryptoStore
. hander
will be called with an updated doc. If the event is change
, than the first argument is a eventName
.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
function changeHandler (eventName, doc) {
console.log(eventName, doc)
}
hoodie.cryptoStore.on('change', changeHandler)
.on('add', function (doc) { // .on returns the cryptoStore
console.log('a doc with ' + doc._id + 'was added')
})
cryptoStore.one(eventName, handler)
Argument | Type | Description | Required |
---|---|---|---|
eventName | String | Event type. One of add , update , remove or change . | Yes |
handler | Function | Event Handler, that will be called one time that event emits. | Yes |
Returns the cryptoStore
. hander
will be called with an updated doc. If the event is change
, than the first argument is a eventName
. After that event is emitted, that handler will be removed.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
function changeHandler (eventName, doc) {
console.log(eventName, doc)
}
hoodie.cryptoStore.one('change', changeHandler)
.one('add', function (doc) { // .on returns the cryptoStore
console.log('a doc with ' + doc._id + 'was added')
})
cryptoStore.off(eventName, handler)
Argument | Type | Description | Required |
---|---|---|---|
eventName | String | Event type. One of add , update , remove or change . | Yes |
handler | Function | Event Handler, that will be removed | Yes |
Returns the cryptoStore
.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
var changeHandler = function (eventName, doc) {
console.log(eventName, doc)
}
hoodie.cryptoStore.on('change', changeHandler)
hoodie.cryptoStore.off('change', changeHandler)
cryptoStore.withIdPrefix(prefix)
Argument | Type | Description | Required |
---|---|---|---|
prefix | String | Section that will be added before every id . | Yes |
Returns the prefixed copy of the cryptoStore
.
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
var userData = hoodie.cryptoStore.withIdPrefix('user/')
// Only emits changes for docs with a 'user/'-prefix.
userData.on('change', function (eventName, doc) {
console.log(eventName, doc)
})
userData.add({
_id: 'test-user', // will be saved as 'user/test-user'
name: 'Tester'
})
.then(function (doc) {
console.log(doc._id) // 'user/test-user'
return userData.find('test-user')
})
.then(function (doc) {
doc.isTester = true
userData.update(doc) // 'user/test-user' and 'test-user' work!
})
cryptoStore.withPassword(password, salt)
Argument | Type | Description | Required |
---|---|---|---|
password | String | A password for encrypting the objects | Yes |
salt | String | A second password part, to add another protection lair. If this is missing a salt will be generated. Which will result in a different encryption! | No |
Resolves with an object
containing the used salt
and a prefixed copy of the cryptoStore
.
{
"salt": "1234567890",
"store": {
"add": function () {},
"withPassword": function () {},
...
}
}
Rejects with:
Name | Description |
---|---|
Error | ... |
Example
var result = hoodie.cryptoStore.withPassword('secretPassword')
.then(function (result) {
var store = result.store
var salt = result.salt
// Only emits changes for docs that are encrypted with this password and salt.
store.on('change', function (eventName, doc) {
console.log(eventName, doc)
})
store.add({foo: 'bar'})
// you must save the salt! Only with the same salt it is the same encryption!
hoodie.cryptoStore.findOrAdd({
_id: 'secondPasswordSalt',
salt: salt
})
})
Event | Description | Arguments |
---|---|---|
add | Is emitted every time a doc is added/created. | doc the added document. |
update | Is emitted every time a doc is updated/changed. | doc the changed document |
remove | Is emitted every time a doc is removed. | doc the removed document. |
change | Is emitted every time a doc is added, updated or removed. | event what did happen? (add , update or remove ), doc the changed document. |
FAQs
End-to-end crypto plugin for the Hoodie client store.
The npm package hoodie-plugin-store-crypto receives a total of 2 weekly downloads. As such, hoodie-plugin-store-crypto popularity was classified as not popular.
We found that hoodie-plugin-store-crypto demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.