Skip to content

Commit

Permalink
Merge pull request #106 from Terreii/pouchdb-hoodie-api
Browse files Browse the repository at this point in the history
Add support for pouchdb-hoodie-api
  • Loading branch information
Terreii authored Aug 29, 2020
2 parents b7fe676 + e25853b commit feb13b0
Show file tree
Hide file tree
Showing 27 changed files with 1,669 additions and 784 deletions.
61 changes: 53 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ 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.

The [PouchDB](https://pouchdb.com/) plugin [pouchdb-hoodie-api](http://hoodiehq.github.io/pouchdb-hoodie-api/)
is also supported!

There is no server side to this plugin!

**Everything of a doc will get encrypted. Except for `_id`, `_rev`, `_deleted`, `_attachments`, `_conflicts` and the `hoodie` object! And _all keys that start with an underscore (\_) will not get encrypted_!**
Expand Down Expand Up @@ -63,7 +66,8 @@ hoodie.cryptoStore.setup('secret')
- Usage
- [Add it to your Hoodie-Client](#add-it-to-your-hoodie-client)
- [with the Hoodie Plugin API](#usage-with-the-hoodie-plugin-api)
- [with Browserify or Webpack](#usage-with-browserify-or-webpack)
- [with a Bundler](#usage-with-a-bundler)
- [with PouchDB and pouchdb-hoodie-api](#usage-with-pouchdb-and-pouchdb-hoodie-api)
- [Get started](#get-started)
- [Sign up / setup / start of using encryption](#setup)
- [Sign in / unlocking](#sign-in)
Expand Down Expand Up @@ -122,7 +126,7 @@ property on your client `hoodie` instance. You can access it with

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

#### Usage with Browserify or Webpack
#### Usage with a Bundler

If you are using a client bundler (e.g. [Browserify](http://browserify.org/)
or [Webpack](https://webpack.js.org)), then you can import it manually.
Expand All @@ -136,17 +140,17 @@ npm install --save-dev hoodie-plugin-store-crypto
Then import it and set it up:

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

var hoodie = new Hoodie({ // create an instance of the hoodie-client
const hoodie = new Hoodie({ // create an instance of the hoodie-client
url: window.location.origin,
PouchDB: PouchDB
})

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

cryptoStore.setup('test')
.then(function () {
Expand All @@ -161,6 +165,47 @@ hoodie.account.on('signout', () => {

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

#### Usage with PouchDB and pouchdb-hoodie-api

To use this plugin with [PouchDB](https://pouchdb.com/) you must install the plugin
[pouchdb-hoodie-api](http://hoodiehq.github.io/pouchdb-hoodie-api/).

```js
npm install --save-dev pouchdb-hoodie-api
```

Setup is like the [usage with Bundler](#usage-with-a-bundler), but you must pass the
the `db.hoodieApi()` from __pouchdb-hoodie-api__. And optionally a remote PouchDB database (or its URL)
for checking and fetching the existence of the encryption setup.

```javascript
import PouchDB from 'pouchdb-browser'
import hoodieApiPlugin from 'pouchdb-hoodie-api'
import CryptoStore from 'hoodie-plugin-store-crypto'

PouchDB.plugin(hoodieApiPlugin)

const db = new PouchDB('local_db')
const remoteDb = new PouchDB('https://example.com/my_db', {
auth: {
username: 'user',
password: 'geheim'
}
})

// sets up cryptoStore
const cryptoStore = new CryptoStore(db.hoodieApi(), {
remote: remoteDb
})

cryptoStore.setup('test')
.then(() => {
console.log('done')
})
```

[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
Expand Down
10 changes: 7 additions & 3 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,9 @@ Setup the __cryptoStore__ and adds it to hoodie.

Argument | Type | Description | Required
---------|--------|-------------|----------
`store` | Object | Hoodie's client-store instance | Yes
`store` | Object | Hoodie's client-store instance or hoodieApi instance from `pouchdb-hoodie-api` | Yes
`options.noPasswordCheckAutoFix` | Boolean | [Deactivate password-check autofix](#v2-update-notes). Default is `false` | No
`options.remote` | PouchDB | Remote database. Used to check and fetch the salt doc. | No

Returns `cryptoStore` API.

Expand All @@ -179,14 +180,14 @@ Example
```javascript
var Store = require('@hoodie/store-client')
var PouchDB = require('pouchdb')
var cryptoStore = require('hoodie-plugin-store-crypto')
var CryptoStore = require('hoodie-plugin-store-crypto')

var store = new Store('mydbname', {
PouchDB: PouchDB,
remote: 'http://localhost:5984/mydbname'
})

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

cryptoStore.setup('test')
.then(function () {
Expand All @@ -204,6 +205,9 @@ hoodie.account.on('signout', () => {

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

If used with [pouchdb-hoodie-api](http://hoodiehq.github.io/pouchdb-hoodie-api/) then the CryptoStore can't
lock itself, too.

### cryptoStore.setup(password)

```javascript
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function CryptoStore (store, options) {
withIdPrefixStore[prefix] = store.withIdPrefix(prefix)
return withIdPrefixStore[prefix]
},
remote: options && options.remote,
noPasswordCheckAutoFix: options != null && Boolean(options.noPasswordCheckAutoFix)
}

Expand Down
34 changes: 29 additions & 5 deletions lib/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var Promise = require('lie')

var createKey = require('./create-key')
var createPasswordCheck = require('./utils/create-password-check')
var pull = require('./utils/pull')
var createResetKeys = require('./helpers/create-reset-keys')

module.exports = setup
Expand Down Expand Up @@ -43,12 +44,35 @@ function setup (store, state, password, salt) {
throw pouchdbErrors.createError(pouchdbErrors.UNAUTHORIZED, 'salt doc already exist!')
}

return store.pull(['hoodiePluginCryptoStore/salt'])
if ('pull' in store) {
return store.pull(['hoodiePluginCryptoStore/salt'])

.catch(function (error) {
console.warn("Couldn't pull docs from remote. Creating new salt!\nError: " + error)
return []
})
.catch(function (error) {
console.warn("Couldn't pull docs from remote. Creating new salt!\nError: " + error)
return []
})
}

if ('db' in store && state.remote != null) {
return pull(['hoodiePluginCryptoStore/salt'], store.db, state.remote)

.catch(function (err) {
if (err.status === pouchdbErrors.UNAUTHORIZED.status) {
console.warn('Could not check the existence of a salt document on a remote db.')
return []
}
if (err.status === 404) {
return [err]
}
throw err
})
}

console.warn(
'Could not check the existence of a salt document on a remote db.\n' +
'Please use the "remote" option when using "pouchdb-hoodie-api".'
)
return []
})

.then(function (obj) {
Expand Down
32 changes: 30 additions & 2 deletions lib/unlock.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ var Promise = require('lie')

var createKey = require('./create-key')
var createPasswordCheck = require('./utils/create-password-check')
var pull = require('./utils/pull')
var decrypt = require('./helpers/decrypt-core')

/**
Expand Down Expand Up @@ -35,8 +36,35 @@ function unlock (store, state, password) {
))
}

// get updated salt docs from remote
return store.pull(['hoodiePluginCryptoStore/salt'])
return Promise.resolve()

// get updated salt docs from remote
.then(function () {
if ('pull' in store) {
return store.pull(['hoodiePluginCryptoStore/salt'])
}

if ('db' in store && state.remote != null) {
return pull(['hoodiePluginCryptoStore/salt'], store.db, state.remote)

.catch(function (err) {
if (err.status === pouchdbErrors.UNAUTHORIZED.status) {
console.warn('Could not check the existence of a salt document on a remote db.')
return []
}
if (err.status === 404) {
return [err]
}
throw err
})
}

console.warn(
'Could not check the existence of a salt document on a remote db.\n' +
'Please use the "remote" option when using "pouchdb-hoodie-api".'
)
return []
})

.then(
function () {
Expand Down
31 changes: 31 additions & 0 deletions lib/utils/pull.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict'

module.exports = pull

var Promise = require('lie')

/**
* Pull documents from a remote database.
* @param {string[]} ids Document ids
* @param {PouchDB.Database} db Local PouchDB database.
* @param {string|PouchDB.Database} remote Remote PouchDB database, or its URL.
*/
function pull (ids, db, remote) {
return new Promise(function (resolve, reject) {
var pulledObjects = []

var replication = db.replicate.from(remote, {
doc_ids: ids
})

replication.on('complete', function () {
resolve(pulledObjects)
})

replication.on('error', reject)

replication.on('change', function (change) {
pulledObjects = pulledObjects.concat(change.docs)
})
})
}
Loading

0 comments on commit feb13b0

Please sign in to comment.