Skip to content

Commit

Permalink
Merge pull request #104 from Terreii/new-init
Browse files Browse the repository at this point in the history
New init
  • Loading branch information
Terreii authored Aug 21, 2020
2 parents bb89a9f + 6cabbd3 commit b7fe676
Show file tree
Hide file tree
Showing 28 changed files with 25,559 additions and 374 deletions.
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,5 @@ typings/
# dotenv environment variables file
.env

# NPM package-lock
package-lock.json

# Hoodie
.hoodie
10 changes: 10 additions & 0 deletions .snyk
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.14.1
ignore: {}
# patches apply the minimum changes required to fix a vulnerability
patch:
SNYK-JS-LODASH-567746:
- lodash:
patched: '2020-05-01T06:47:06.828Z'
- '@hoodie/store-client > lodash':
patched: '2020-05-01T06:47:06.828Z'
3 changes: 2 additions & 1 deletion .textlintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"alex": {
"allow": [
reject,
rejects
rejects,
special
]
},
"common-misspellings": true,
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
language: node_js

node_js:
- "8"
- "10"
- "12"
- "14"
- "node"

# Trigger a push build on latest and greenkeeper branches + PRs build on every branches
Expand Down
25 changes: 21 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,26 @@ var hoodie = new Hoodie({ // create an instance of the hoodie-client
PouchDB: PouchDB
})

cryptoStore(hoodie) // sets up hoodie.cryptoStore
// sets up hoodie.cryptoStore
var cryptoStore = new CryptoStore(hoodie.store, { /* some options */})

cryptoStore.setup('test')
.then(function () {
console.log('done')
})

// lock the cryptoStore on sign out
hoodie.account.on('signout', () => {
cryptoStore.lock()
})
```

[Back to top](#table-of-contents)

### Get started

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.
your app, a second password, or a derived password.

There are 5 use-cases you must put in place:

Expand All @@ -170,7 +181,7 @@ you newly added this plugin.

Use [`cryptoStore.setup(password, [salt])`](#cryptostoresetuppassword) to set the
encryption password. __`cryptoStore.setup(password, [salt])` will not unlock your cryptoStore instance__
(just like hoodie.account.signUp)!
(like hoodie.account.signUp)!

A salt is a second part of a password. `cryptoStore.setup(password, [salt])` will save the generated salt in `hoodiePluginCryptoStore/salt`, and use it. [More about what the salt is](http://www.passwordbreeder.com/page/salt).

Expand Down Expand Up @@ -218,11 +229,12 @@ async function signIn (username, password, cryptoPassword) {

#### Sign out

`cryptoStore` will automatically listen to [`account.on('signout')`](http://docs.hood.ie/en/latest/api/client/hoodie.account.html#events) events. And locks itself if it emits an event. You don't need to add any setup for it.
If you use hoodie's plugin system, then `cryptoStore` will automatically listen to [`account.on('signout')`](http://docs.hood.ie/en/latest/api/client/hoodie.account.html#events) events. And locks itself if it emits an event. You don't need to add any setup for it.

Use-cases for the [`cryptoStore.lock()`](#cryptostorelock) method are:
- a lock after a timeout functionality
- lock the store in a save way when closing an tab.
- lock on sign out, if you didn't use hoodie's plugin system.

```javascript
window.addEventListener('beforeunload', function (event) {
Expand All @@ -231,6 +243,11 @@ window.addEventListener('beforeunload', function (event) {
// It overwrites the key data 10 times.
hoodie.cryptoStore.lock()
})

// or on sign out
hoodie.account.on('signout', () => {
cryptoStore.lock()
})
```

[Back to top](#table-of-contents)
Expand Down
37 changes: 23 additions & 14 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- [Documents from this plugin](#documents-from-this-plugin)
- [Concepts of cryptoStore.withPassword](#concepts-of-cryptostorewithpassword)
- [Methods](#methods)
- [cryptoStore (setup function)](#cryptostore-setup-function)
- [Constructor](#constructor)
- [cryptoStore.setup(password)](#cryptostoresetuppassword)
- [cryptoStore.setup(password, salt)](#cryptostoresetuppassword-salt)
- [cryptoStore.unlock(password)](#cryptostorelock)
Expand Down Expand Up @@ -60,7 +60,7 @@ Those concepts/rules apply to all methods.

**Everything of a doc will get encrypted. Except for `_id`, `_rev`, `_deleted`, `_attachments`, `_conflicts` and the `hoodie` object!**

Also _all keys that start with an underscore (\_) will not get encrypted_! Because they are __special document members__ used by CouchDB and PouchDB! To deactivated this set the *plugin option* `notHandleSpecialDocumentMembers` to `true`.
Also _all keys that start with an underscore (\_) will not get encrypted_! Because they are __special document members__ used by CouchDB and PouchDB!

**Don't save private data in the `_id`**!

Expand Down Expand Up @@ -158,43 +158,52 @@ It allows to encrypt documents with a different password (and salt). It is like

## Methods

### cryptoStore (setup function)
### Constructor

```javascript
cryptoStore(hoodie, options)
new CryptoStore(store, options)
```

Setup the __cryptoStore__ and adds it to hoodie.

Argument | Type | Description | Required
---------|--------|-------------|----------
`hoodie` | Object | Hoodie client instance | Yes
`store` | Object | Hoodie's client-store instance | Yes
`options.noPasswordCheckAutoFix` | Boolean | [Deactivate password-check autofix](#v2-update-notes). Default is `false` | No
`options.notHandleSpecialDocumentMembers` | Boolean | [Encrypt all fields with a key that start with an `_`](#what-gets-encrypted). Default is `false` | No

Returns `undefined`
Returns `cryptoStore` API.

__Required if you setup your hoodie-client yourself! Else Hoodie does it for you!__

Example
```javascript
var Hoodie = require('@hoodie/client')
var Store = require('@hoodie/store-client')
var PouchDB = require('pouchdb')
var cryptoStore = require('hoodie-plugin-store-crypto')

var hoodie = new Hoodie({ // create an instance of the hoodie-client
url: window.location.origin,
PouchDB: PouchDB
var store = new Store('mydbname', {
PouchDB: PouchDB,
remote: 'http://localhost:5984/mydbname'
})

cryptoStore(hoodie) // sets up hoodie.cryptoStore
var cryptoStore = new CryptoStore(store, { /* some options */}) // sets up hoodie.cryptoStore

hoodie.cryptoStore.setup('test')
cryptoStore.setup('test')
.then(function () {
console.log('done')
})
```

To lock the cryptoStore on sign out you have to listen to [hoodie's `signout` event](https://github.com/hoodiehq/hoodie-account-client#events).

```javascript
hoodie.account.on('signout', () => {
cryptoStore.lock()
})
```

If you use Hoodie's plugin API, then locking on sign out is already setup for you.

### cryptoStore.setup(password)

```javascript
Expand Down Expand Up @@ -1448,7 +1457,7 @@ Name | Status | Description | Why
------|--------|--------|-------
unauthorized | 401 | Name or password is incorrect. | This plugin wasn't unlocked yet.
bad_request | 400 | Data was undefined. Data is must be an object! | `encrypted` was `undefined` or `null`.
bad_request | 400 | Data was invalid. It must be an object with data, tag and nonce! | `encrypted` didn't contain `data`, `tag` or `nonce`. All three must be strings.
bad_request | 400 | Data was not an Object with the required fields. It must be an object with data, tag and nonce! | `encrypted` didn't contain `data`, `tag` or `nonce`. All three must be strings.
_ | _ | Unsupported state or unable to authenticate data | `aad` (additional authentication data) didn't match.

### cryptoStore.on()
Expand Down
32 changes: 32 additions & 0 deletions docs/update.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ It will list all changes, you have to make, if you update to:
- [v2.2](#v22-update-notes)
- [v2.3](#v23-update-notes)
- [v3](#v3-update-notes)
- [v4](#v4-update-notes)

## v2 Update Notes

Expand Down Expand Up @@ -175,3 +176,34 @@ If you are still using node v6: please migrate to a newer version! Node version
All document members/fields that start with an `_` will now not encrypted.

To deactivate it set the option `notHandleSpecialDocumentMembers` to `true`.

## v4 Update Notes

### Constructor export

The main export (`require('hoodie-plugin-crypto-store')`) is now a constructor. It requires a hoodie-store
and optionally options.

```javascript
const CryptoStore = require('hoodie-plugin-crypto-store')

const cryptoStore = new CryptoStore(hoodie.store, {
// some options
})
```

The constructor will not listen to `signout` events. If you want to lock the CryptoStore instance,
then you have to manually listen to [hoodie's `signout` event](https://github.com/hoodiehq/hoodie-account-client#events).

```javascript
hoodie.account.on('signout', () => {
cryptoStore.lock()
})
```

If you use hoodie's plugin system, then nothing will change for you.

### Removing of notHandleSpecialDocumentMembers-option

The `notHandleSpecialDocumentMembers` option got removed with v4.
All fields that start with an "_" will not get encrypted!
39 changes: 3 additions & 36 deletions hoodie/client.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,11 @@
'use strict'

var bindFunctions = require('../lib/bind-functions')

module.exports = cryptoStore

function cryptoStore (hoodie, options) {
var withIdPrefixStore = {} // store prefix APIs from hoodie-store. Workaround for #42

var state = {
getWithPrefixAPI: function (prefix) { // get a prefix API. This is a workaround for #42
if (prefix == null) {
return hoodie.store
}

if (withIdPrefixStore[prefix] != null) {
return withIdPrefixStore[prefix]
}
var CryptoStore = require('../index')

withIdPrefixStore[prefix] = hoodie.store.withIdPrefix(prefix)
return withIdPrefixStore[prefix]
},
handleSpecialMembers: options == null || !options.notHandleSpecialDocumentMembers,
noPasswordCheckAutoFix: options != null && Boolean(options.noPasswordCheckAutoFix)
}

if (state.noPasswordCheckAutoFix) {
console.warn(
'Salt doc without a password check is deprecated!\n\n' +
'Read more at https://github.com/Terreii/hoodie-plugin-store-crypto/' +
'blob/latest/docs/update.md#v3-update-notes'
)
}

var handler = {
on: hoodie.store.on,
once: hoodie.store.one,
removeListener: hoodie.store.off
}

hoodie.cryptoStore = bindFunctions(hoodie.store, state, null, handler, true)
function cryptoStore (hoodie, options) {
hoodie.cryptoStore = new CryptoStore(hoodie.store, options)

if ('account' in hoodie && typeof hoodie.account.on === 'function') {
hoodie.account.on('signout', hoodie.cryptoStore.lock)
Expand Down
45 changes: 44 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1 +1,44 @@
module.exports = require('./hoodie/client')
'use strict'

module.exports = CryptoStore

var bindFunctions = require('./lib/bind-functions')

function CryptoStore (store, options) {
if (!(this instanceof CryptoStore)) return new CryptoStore(store, options)

var withIdPrefixStore = {} // store prefix APIs from hoodie-store. Workaround for #42

var state = {
getWithPrefixAPI: function (prefix) { // get a prefix API. This is a workaround for #42
if (prefix == null) {
return store
}

if (prefix in withIdPrefixStore) {
return withIdPrefixStore[prefix]
}

withIdPrefixStore[prefix] = store.withIdPrefix(prefix)
return withIdPrefixStore[prefix]
},
noPasswordCheckAutoFix: options != null && Boolean(options.noPasswordCheckAutoFix)
}

if (state.noPasswordCheckAutoFix) {
console.warn(
'Salt doc without a password check is deprecated!\n\n' +
'Read more at https://github.com/Terreii/hoodie-plugin-store-crypto/' +
'blob/latest/docs/update.md#v3-update-notes'
)
}

var handler = {
on: store.on,
once: store.one,
removeListener: store.off
}

const api = bindFunctions(store, state, null, handler, true)
Object.assign(this, api)
}
2 changes: 1 addition & 1 deletion lib/encrypt-doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function encryptDoc (state, doc, prefix) {
Object.getOwnPropertyNames(doc).forEach(function (key) {
if (doc[key] === undefined || key === '__cy_ignore') return

if ((state.handleSpecialMembers && key.charAt(0) === '_') || includes(docIgnore, key)) {
if (key.charAt(0) === '_' || includes(docIgnore, key)) {
outDoc[key] = doc[key]
} else {
encryptDoc[key] = doc[key]
Expand Down
Loading

0 comments on commit b7fe676

Please sign in to comment.