From 9519fb517af488a6dc3e68a6be0f0e903081ba4a Mon Sep 17 00:00:00 2001 From: Marten de Vries Date: Tue, 12 Aug 2014 21:59:58 +0200 Subject: [PATCH 01/14] New: PouchDB Seamless Auth; PouchDB Security. Lots of fixes. PouchDB 3.0. --- README.md | 9 +++ index.js | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 45 +++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 README.md create mode 100644 index.js create mode 100644 package.json diff --git a/README.md b/README.md new file mode 100644 index 00000000..f193a5c2 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +pouchdb-seamless-auth +===================== + +Seamless switching between online (CouchDB) and offline (PouchDB) +authentication. + +See also [pouchdb-seamless-auth's documentation](http://pythonhosted.org/Python-PouchDB/js-plugins.html#pouchdb-seamless-auth-plug-in) + +[Website of this plug-in and a few others](http://python-pouchdb.marten-de-vries.nl/plugins.html) diff --git a/index.js b/index.js new file mode 100644 index 00000000..f7550af2 --- /dev/null +++ b/index.js @@ -0,0 +1,183 @@ +/* + Copyright 2014, Marten de Vries + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +"use strict"; + +var Auth = require("pouchdb-auth"); +var extend = require("extend"); +var Promise = require("pouchdb-promise"); +var nodify = require("promise-nodify"); + +var PouchDB, local, remote; +var cacheInvalidated; +var cache; + +module.exports = function (thePouchDB) { + PouchDB = thePouchDB; + local = new PouchDB("_users"); + + return Auth.useAsAuthenticationDB.call(local) + .then(invalidateCache) + .then(function () { + extend(PouchDB, api); + }); +}; + +function invalidateCache(passthrough) { + cacheInvalidated = true; + + return passthrough; +} + +var api = {}; +api.setSeamlessAuthRemoteDB = function (remoteName, remoteOptions, callback) { + remote = new PouchDB(remoteName, remoteOptions); + + var promise = Auth.useAsAuthenticationDB.call(remote) + .then(invalidateCache); + + nodify(promise, callback); + return promise; +}; + +api.unsetSeamlessAuthRemoteDB = function () { + remote = undefined; + invalidateCache(); +}; + +api.invalidateSeamlessAuthCache = function () { + invalidateCache(); +}; + +api.seamlessSession = function (opts, callback) { + //Getting the session is something that can happen quite often in a + //row. HTTP is slow (and _session is not HTTP cached), so a manual + //cache is implemented here. + var args = parseArgs(opts, callback); + if (cacheInvalidated) { + cache = callFromAvailableSource("session", args.opts) + .then(function (info) { + if (info.resp.userCtx.name !== null) { + return startReplication(info.resp.userCtx.name, info); + } else { + return info; + } + }) + .then(returnResp); + cacheInvalidated = false; + } + nodify(cache, args.callback); + return cache; +}; + +api.seamlessLogIn = function (username, password, opts, callback) { + var args = parseArgs(opts, callback); + var promise = callFromAvailableSource("logIn", username, password, args.opts, args.callback) + .then(startReplication.bind(null, username)) + .then(invalidateCache) + .then(returnResp); + nodify(promise, args.callback); + return promise; +}; + +api.seamlessLogOut = function (opts, callback) { + var args = parseArgs(opts, callback); + var promise = callFromAvailableSource("logOut", args.opts, args.callback) + .then(invalidateCache) + .then(returnResp); + nodify(promise, args.callback); + return promise; +}; + +api.seamlessSignUp = function (username, password, opts, callback) { + var args = parseArgs(opts, callback); + var promise = callFromAvailableSource("signUp", username, password, args.opts, args.callback) + .then(startReplication.bind(null, username)) + .then(invalidateCache) + .then(returnResp); + nodify(promise, callback); + return promise; +}; + +function callFromAvailableSource(name/*, arg1, ...*/) { + var args = Array.prototype.slice.call(arguments, 1); + return Promise.resolve() + .then(function () { + //promisifies the 'undefined has no attribute apply' error too + //when in a then-function instead of on top. + return remote[name].apply(remote, args) + .then(function (resp) { + return { + type: "remote", + resp: resp + }; + }); + }) + .catch(function () { + return local[name].apply(local, args) + .then(function (resp) { + return { + type: "local", + resp: resp + }; + }); + }); +} + +function returnResp(info) { + return info.resp; +} + +function parseArgs(opts, callback) { + if (typeof opts === "function") { + callback = opts; + opts = {}; + } + return { + callback: callback, + opts: opts + }; +} + +function startReplication(username, info) { + //can't use real replication because the changes feed of _users isn't + //publicly accessable for non-admins. + if (info.type === "remote") { + //can only 'replicate' when the remote db is available. + var getRemote = remote.get("org.couchdb.user:" + username, {revs: true}) + .catch(useEmptyDoc); + var getLocal = local.get("org.couchdb.user:" + username, {revs: true}) + .catch(useEmptyDoc); + Promise.all([getRemote, getLocal]) + .then(Function.prototype.apply.bind(function (remoteDoc, localDoc) { + if (remoteDoc._rev > localDoc._rev) { + local.bulkDocs([remoteDoc], {new_edits: false}); + } else if (remoteDoc._rev < localDoc._rev) { + remote.bulkDocs([localDoc], {new_edits: false}); + } else { + //both were up-to-date already. Prevent cache invalidation by + //returning directly. + return; + } + invalidateCache(); + }, null)); + } + return info; +} + +function useEmptyDoc() { + return {_rev: "0"}; +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..65b1a8e6 --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "pouchdb-seamless-auth", + "version": "0.1.0", + "main": "index.js", + "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", + "repository": { + "type": "bzr", + "url": "http://bazaar.launchpad.net/~marten-de-vries/python-pouchdb/0.x" + }, + "bugs": "https://bugs.launchpad.net/python-pouchdb", + "keywords": [ + "pouch", + "pouchdb", + "couch", + "couchdb", + "users", + "authentication", + "auth", + "seamless", + "online", + "offline" + ], + "license": "Apache-2.0", + "author": "Marten de Vries", + "dependencies": { + "pouchdb-promise": "^0.0.0", + "extend": "^1.2.1", + "promise-nodify": "^1.0.0", + "pouchdb-auth": "^0.1.0" + }, + "devDependencies": { + "browserify": "^4.1.8", + "uglify-js": "^2.4.13", + "es3ify": "^0.1.3" + }, + "scripts": { + "build-js": "mkdir -p ../../dist && browserify index.js -s SeamlessAuth -o ../../dist/pouchdb-seamless-auth.js", + "build": "npm run build-js; cd ../../dist; uglifyjs pouchdb-seamless-auth.js -mc > pouchdb-seamless-auth.min.js" + }, + "browserify": { + "transform": [ + "es3ify" + ] + } +} From 02af30190ae4dbd9d2c94ad646fe121ed0e9df3f Mon Sep 17 00:00:00 2001 From: Marten de Vries Date: Mon, 1 Sep 2014 19:25:32 +0200 Subject: [PATCH 02/14] JS is all at 1.0.0 at least now & published. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 65b1a8e6..0a9fb4c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pouchdb-seamless-auth", - "version": "0.1.0", + "version": "1.0.0", "main": "index.js", "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", "repository": { @@ -26,7 +26,7 @@ "pouchdb-promise": "^0.0.0", "extend": "^1.2.1", "promise-nodify": "^1.0.0", - "pouchdb-auth": "^0.1.0" + "pouchdb-auth": "^1.0.0" }, "devDependencies": { "browserify": "^4.1.8", From 0ebf9b0e32c5a46a27b37d2ae90de92a83d2bef6 Mon Sep 17 00:00:00 2001 From: Marten de Vries Date: Tue, 13 Jan 2015 12:38:38 +0100 Subject: [PATCH 03/14] Warning on pouchdb-seamless-auth --- README.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f193a5c2..04a2aa8b 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,13 @@ pouchdb-seamless-auth Seamless switching between online (CouchDB) and offline (PouchDB) authentication. +**WARNING**: This plug-in stores password hashes in a local PouchDB. In +for example internet cafes, this is not a smart thing to do. In your +app, you should include a checkbox 'I trust this computer' and only use +**pouchdb-seamless-auth** when it is checked. Otherwise, you can fall +back to **pouchdb-auth**. This functionality might be implemented as +part of the plug-in in the future. + See also [pouchdb-seamless-auth's documentation](http://pythonhosted.org/Python-PouchDB/js-plugins.html#pouchdb-seamless-auth-plug-in) [Website of this plug-in and a few others](http://python-pouchdb.marten-de-vries.nl/plugins.html) diff --git a/package.json b/package.json index 0a9fb4c1..60d4ec20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pouchdb-seamless-auth", - "version": "1.0.0", + "version": "1.0.1", "main": "index.js", "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", "repository": { From 9aee6144279a75d0366f743ebcd7e25d349f299a Mon Sep 17 00:00:00 2001 From: Marten de Vries Date: Wed, 19 Aug 2015 11:00:58 +0200 Subject: [PATCH 04/14] v1.0.2; moved to github --- .gitignore | 2 ++ package.json | 17 ++++------------- 2 files changed, 6 insertions(+), 13 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f06235c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/package.json b/package.json index 60d4ec20..ef0f2481 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,9 @@ { "name": "pouchdb-seamless-auth", - "version": "1.0.1", + "version": "1.0.2", "main": "index.js", "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", - "repository": { - "type": "bzr", - "url": "http://bazaar.launchpad.net/~marten-de-vries/python-pouchdb/0.x" - }, - "bugs": "https://bugs.launchpad.net/python-pouchdb", + "repository": "marten-de-vries/pouchdb-seamless-auth", "keywords": [ "pouch", "pouchdb", @@ -34,12 +30,7 @@ "es3ify": "^0.1.3" }, "scripts": { - "build-js": "mkdir -p ../../dist && browserify index.js -s SeamlessAuth -o ../../dist/pouchdb-seamless-auth.js", - "build": "npm run build-js; cd ../../dist; uglifyjs pouchdb-seamless-auth.js -mc > pouchdb-seamless-auth.min.js" - }, - "browserify": { - "transform": [ - "es3ify" - ] + "build-js": "mkdir -p dist && browserify index.js -s SeamlessAuth -g es3ify -o dist/pouchdb-seamless-auth.js", + "build": "npm run build-js; cd dist; uglifyjs pouchdb-seamless-auth.js -mc > pouchdb-seamless-auth.min.js" } } From a773d17a489f2bd21bef1b8a7aef80a1784abbd3 Mon Sep 17 00:00:00 2001 From: Marten de Vries Date: Sun, 27 Dec 2015 13:12:59 +0100 Subject: [PATCH 05/14] (pouchdb/express-pouchdb#232) - Modernize pouchdb-seamless-auth --- .gitignore | 1 + .travis.yml | 30 ++++++++++++++++ README.md | 83 ++++++++++++++++++++++++++++++++++++++++-- index.js | 70 ++++++++++++++++++------------------ package.json | 70 ++++++++++++++++++------------------ test/features.js | 89 ++++++++++++++++++++++++++++++++++++++++++++++ test/signatures.js | 12 +++++++ test/utils.js | 10 ++++++ 8 files changed, 294 insertions(+), 71 deletions(-) create mode 100644 .travis.yml create mode 100644 test/features.js create mode 100644 test/signatures.js create mode 100644 test/utils.js diff --git a/.gitignore b/.gitignore index f06235c4..0e75fe55 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules dist +coverage diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..4a63e93e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +sudo: false +language: node_js + +cache: + directories: + - node_modules + +node_js: + - "0.10" + +services: + - couchdb + +before_install: + - npm i -g npm@^2.0.0 + +before_script: + - npm prune + +script: npm run $COMMAND + +env: + matrix: + - COMMAND='helper -- lint' + - COMMAND='helper -- js-test' + - COMMAND='build' + +#after_success: +# - npm run helper -- semantic-release + diff --git a/README.md b/README.md index 04a2aa8b..97a10341 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ pouchdb-seamless-auth ===================== +[![Build Status](https://travis-ci.org/marten-de-vries/pouchdb-seamless-auth.svg?branch=master)](https://travis-ci.org/marten-de-vries/pouchdb-seamless-auth) +[![Dependency Status](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth.svg)](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth) +[![devDependency Status](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth/dev-status.svg)](https://david-dm.org/marten-de-vries/pouchdb-seamless-auth#info=devDependencies) + Seamless switching between online (CouchDB) and offline (PouchDB) authentication. @@ -11,6 +15,81 @@ app, you should include a checkbox 'I trust this computer' and only use back to **pouchdb-auth**. This functionality might be implemented as part of the plug-in in the future. -See also [pouchdb-seamless-auth's documentation](http://pythonhosted.org/Python-PouchDB/js-plugins.html#pouchdb-seamless-auth-plug-in) +API +--- + +NodeJS package name: [pouchdb-seamless-auth](https://www.npmjs.org/package/pouchdb-seamless-auth) +Browser object name: ``window.SeamlessAuth`` + +This plug-in provides a convenience layer on top of the PouchDB Auth +plug-in. By default, it users a local database named ``_users`` as +backend for its log in, log out and get session actions. But, when you +set a remote database, that local database is synced with the given +database. In other words, it allows you to let your user log in one +time using the remote database, and from that moment on you can also the +session functions while offline! Very handy when using a per-user +database set up that PouchDB syncs. + +Instead of passing this plug-in to the ``PouchDB.plugin()`` function, install +it like this: + +```javascript +//NodeJS +require("pouchdb-seamless-auth")(PouchDB) + +//Browser +SeamlessAuth(PouchDB) +``` + +After that is finished (a promise is returned to help determine when that is), +all functions documented below are available on the ``PouchDB`` object. + +### PouchDB.setSeamlessAuthRemoteDB(remoteName[, remoteOptions[, callback]]) + +Set a remote database to be seamlessly synced to. + +**Parameters**: + +- *string* remoteName: The url to the remote database. Passed to the + ``PouchDB`` constructor as the first argument. +- *object* remoteOptions: Options to pass on to the ``PouchDB`` constructor + as its second argument. +- *function* callback: An alternative for the returned promise. + +**Returns**: a promise, which resolves to nothing when the remote database is +completely set up. + +### PouchDB.unsetSeamlessAuthRemoteDB() + +A synchronous function. Undos what ``PouchDB.setSeamlessAuthRemoteDB()`` did. + +**Returns**: nothing. + +### PouchDB.seamlessSession([opts[, callback]]) + +See **pouchdb-auth**'s ``db.session()``. + +### PouchDB.seamlessLogIn(username, password, [opts[, callback]]) + +See **pouchdb-auth**'s ``db.logIn()``. + +### PouchDB.seamlessLogOut([opts[, callback]]) + +See **pouchdb-auth**'s ``db.logOut()``. + +### PouchDB.seamlessSignUp(username, password, [opts[, callback]]) + +See **pouchdb-auth**'s ``db.signUp()``. + +### PouchDB.invalidateSeamlessAuthCache() + +Used to invalidate the cache manually. + +This is a synchronous function. Because an application might call +``PouchDB.seamlessSession()`` a lot of times, that method is cached. For most +of the time, you don't have to worry about that, because log in, log out and +sign up all invalidate that cache, making it pretty much unnoticable. There is +one known exception: when changing the user document in ``_users`` manually. +Call this to invalidate the cache when you do that. -[Website of this plug-in and a few others](http://python-pouchdb.marten-de-vries.nl/plugins.html) +**Returns**: nothing. diff --git a/index.js b/index.js index f7550af2..cfeada3e 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ /* - Copyright 2014, Marten de Vries + Copyright 2014-2015, Marten de Vries Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,12 +14,12 @@ limitations under the License. */ -"use strict"; +'use strict'; -var Auth = require("pouchdb-auth"); -var extend = require("extend"); -var Promise = require("pouchdb-promise"); -var nodify = require("promise-nodify"); +var Auth = require('pouchdb-auth'); +var extend = require('extend'); +var Promise = require('pouchdb-promise'); +var nodify = require('promise-nodify'); var PouchDB, local, remote; var cacheInvalidated; @@ -27,7 +27,7 @@ var cache; module.exports = function (thePouchDB) { PouchDB = thePouchDB; - local = new PouchDB("_users"); + local = new PouchDB('_users'); return Auth.useAsAuthenticationDB.call(local) .then(invalidateCache) @@ -63,12 +63,12 @@ api.invalidateSeamlessAuthCache = function () { }; api.seamlessSession = function (opts, callback) { - //Getting the session is something that can happen quite often in a - //row. HTTP is slow (and _session is not HTTP cached), so a manual - //cache is implemented here. + // Getting the session is something that can happen quite often in a row. HTTP + // is slow (and _session is not HTTP cached), so a manual cache is implemented + // here. var args = parseArgs(opts, callback); if (cacheInvalidated) { - cache = callFromAvailableSource("session", args.opts) + cache = callFromAvailableSource('session', args.opts) .then(function (info) { if (info.resp.userCtx.name !== null) { return startReplication(info.resp.userCtx.name, info); @@ -85,7 +85,7 @@ api.seamlessSession = function (opts, callback) { api.seamlessLogIn = function (username, password, opts, callback) { var args = parseArgs(opts, callback); - var promise = callFromAvailableSource("logIn", username, password, args.opts, args.callback) + var promise = callFromAvailableSource('logIn', username, password, args.opts) .then(startReplication.bind(null, username)) .then(invalidateCache) .then(returnResp); @@ -95,7 +95,7 @@ api.seamlessLogIn = function (username, password, opts, callback) { api.seamlessLogOut = function (opts, callback) { var args = parseArgs(opts, callback); - var promise = callFromAvailableSource("logOut", args.opts, args.callback) + var promise = callFromAvailableSource('logOut', args.opts) .then(invalidateCache) .then(returnResp); nodify(promise, args.callback); @@ -104,11 +104,11 @@ api.seamlessLogOut = function (opts, callback) { api.seamlessSignUp = function (username, password, opts, callback) { var args = parseArgs(opts, callback); - var promise = callFromAvailableSource("signUp", username, password, args.opts, args.callback) + var promise = callFromAvailableSource('signUp', username, password, args.opts) .then(startReplication.bind(null, username)) .then(invalidateCache) .then(returnResp); - nodify(promise, callback); + nodify(promise, args.callback); return promise; }; @@ -116,21 +116,21 @@ function callFromAvailableSource(name/*, arg1, ...*/) { var args = Array.prototype.slice.call(arguments, 1); return Promise.resolve() .then(function () { - //promisifies the 'undefined has no attribute apply' error too - //when in a then-function instead of on top. - return remote[name].apply(remote, args) - .then(function (resp) { - return { - type: "remote", - resp: resp - }; - }); + // promisifies the 'undefined has no attribute apply' error too when in a + // then-function instead of on top. + return remote[name].apply(remote, args); + }) + .then(function (resp) { + return { + type: 'remote', + resp: resp + }; }) .catch(function () { return local[name].apply(local, args) .then(function (resp) { return { - type: "local", + type: 'local', resp: resp }; }); @@ -142,7 +142,7 @@ function returnResp(info) { } function parseArgs(opts, callback) { - if (typeof opts === "function") { + if (typeof opts === 'function') { callback = opts; opts = {}; } @@ -153,13 +153,13 @@ function parseArgs(opts, callback) { } function startReplication(username, info) { - //can't use real replication because the changes feed of _users isn't - //publicly accessable for non-admins. - if (info.type === "remote") { - //can only 'replicate' when the remote db is available. - var getRemote = remote.get("org.couchdb.user:" + username, {revs: true}) + // can't use real replication because the changes feed of _users isn't + // publicly accessable for non-admins. + if (info.type === 'remote') { + // can only 'replicate' when the remote db is available. + var getRemote = remote.get('org.couchdb.user:' + username, {revs: true}) .catch(useEmptyDoc); - var getLocal = local.get("org.couchdb.user:" + username, {revs: true}) + var getLocal = local.get('org.couchdb.user:' + username, {revs: true}) .catch(useEmptyDoc); Promise.all([getRemote, getLocal]) .then(Function.prototype.apply.bind(function (remoteDoc, localDoc) { @@ -168,8 +168,8 @@ function startReplication(username, info) { } else if (remoteDoc._rev < localDoc._rev) { remote.bulkDocs([localDoc], {new_edits: false}); } else { - //both were up-to-date already. Prevent cache invalidation by - //returning directly. + // both were up-to-date already. Prevent cache invalidation by + // returning directly. return; } invalidateCache(); @@ -179,5 +179,5 @@ function startReplication(username, info) { } function useEmptyDoc() { - return {_rev: "0"}; + return {_rev: '0'}; } diff --git a/package.json b/package.json index ef0f2481..0327478c 100644 --- a/package.json +++ b/package.json @@ -1,36 +1,38 @@ { - "name": "pouchdb-seamless-auth", - "version": "1.0.2", - "main": "index.js", - "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", - "repository": "marten-de-vries/pouchdb-seamless-auth", - "keywords": [ - "pouch", - "pouchdb", - "couch", - "couchdb", - "users", - "authentication", - "auth", - "seamless", - "online", - "offline" - ], - "license": "Apache-2.0", - "author": "Marten de Vries", - "dependencies": { - "pouchdb-promise": "^0.0.0", - "extend": "^1.2.1", - "promise-nodify": "^1.0.0", - "pouchdb-auth": "^1.0.0" - }, - "devDependencies": { - "browserify": "^4.1.8", - "uglify-js": "^2.4.13", - "es3ify": "^0.1.3" - }, - "scripts": { - "build-js": "mkdir -p dist && browserify index.js -s SeamlessAuth -g es3ify -o dist/pouchdb-seamless-auth.js", - "build": "npm run build-js; cd dist; uglifyjs pouchdb-seamless-auth.js -mc > pouchdb-seamless-auth.min.js" - } + "name": "pouchdb-seamless-auth", + "version": "1.0.3", + "main": "index.js", + "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", + "repository": { + "type": "git", + "url": "https://github.com/marten-de-vries/pouchdb-seamless-auth.git" + }, + "keywords": [ + "pouch", + "pouchdb", + "couch", + "couchdb", + "users", + "authentication", + "auth", + "seamless", + "online", + "offline" + ], + "license": "Apache-2.0", + "author": "Marten de Vries", + "dependencies": { + "pouchdb-promise": "^0.0.0", + "extend": "^1.2.1", + "promise-nodify": "^1.0.0", + "pouchdb-auth": "^2.0.0" + }, + "devDependencies": { + "pouchdb-plugin-helper": "^2.0.1" + }, + "scripts": { + "helper": "./node_modules/.bin/pouchdb-plugin-helper", + "test": "npm run helper -- test", + "build": "npm run helper -- build SeamlessAuth" + } } diff --git a/test/features.js b/test/features.js new file mode 100644 index 00000000..00498eae --- /dev/null +++ b/test/features.js @@ -0,0 +1,89 @@ +import {waitUntilReady, cleanup, PouchDB, should, BASE_URL, HTTP_AUTH} from './utils'; + +const url = BASE_URL + '/_users'; + +describe('sync seamless auth tests without remote', () => { + before(waitUntilReady); + afterEach(cleanup); + + it('test', async () => { + const resp = await PouchDB.seamlessSignUp('username', 'password'); + resp.ok.should.be.ok; + const s = await PouchDB.seamlessSession(); + s.info.authentication_db.should.equal('_users'); + should.equal(s.userCtx.name, null); + (await PouchDB.seamlessLogIn('username', 'password')).name.should.equal('username'); + (await PouchDB.seamlessLogOut()).ok.should.be.ok; + }); +}); + +describe('sync seamless auth tests with remote', () => { + let remoteDB, localDB; + before(waitUntilReady); + beforeEach(async () => { + await PouchDB.setSeamlessAuthRemoteDB(url, {auth: HTTP_AUTH}); + remoteDB = new PouchDB(url, {auth: HTTP_AUTH}); + localDB = new PouchDB('_users'); + }); + afterEach(async () => { + // local + await cleanup(); + // remote + PouchDB.unsetSeamlessAuthRemoteDB() + try { + await remoteDB.remove(await remoteDB.get('org.couchdb.user:username')); + } catch (err) {/* already not there apparently*/} + }); + + it('test', async () => { + const resp = await PouchDB.seamlessSignUp('username', 'password'); + resp.ok.should.be.ok; + + // check replication from remote to local + let doc; + // ethernal loop when the test doesn't pass + do { + try { + doc = await localDB.get(resp.id); + } catch (err) {/* document not yet replicated */} + } while (!doc); + + // check if online session + (await PouchDB.seamlessLogIn('username', 'password')).name.should.equal('username'); + const s = await PouchDB.seamlessSession(); + s.info.authentication_handlers.should.contain('cookie'); + + // update the local document and check if replicated back + doc.abc = 1; + localDB.put(doc); + + // triggers the replication + PouchDB.invalidateSeamlessAuthCache(); + await PouchDB.seamlessSession(); + + let remoteDoc; + do { + remoteDoc = await remoteDB.get(resp.id); + } while(!remoteDoc.abc); + + // test caching code + await PouchDB.seamlessSession(); + await PouchDB.seamlessSession(); + + // log out + (await PouchDB.seamlessLogOut()).ok.should.be.ok; + }); +}); + +describe('async seamless auth tests', () => { + before(waitUntilReady); + afterEach(cleanup); + + it('set remote db', done => { + PouchDB.setSeamlessAuthRemoteDB(url, {auth: HTTP_AUTH}, (err, resp) => { + should.not.exist(resp); + should.not.exist(PouchDB.unsetSeamlessAuthRemoteDB()); + done(err); + }); + }); +}); diff --git a/test/signatures.js b/test/signatures.js new file mode 100644 index 00000000..51174abc --- /dev/null +++ b/test/signatures.js @@ -0,0 +1,12 @@ +import {waitUntilReady, cleanup, PouchDB} from './utils'; + +describe('signatures', () => { + before(waitUntilReady); + afterEach(cleanup); + + it('seamless auth', () => { + const promise = PouchDB.seamlessSession(() => {}); + promise.then.should.be.ok; + promise.catch.should.be.ok; + }); +}); diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 00000000..b68d3bf8 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,10 @@ +import stuff from 'pouchdb-plugin-helper/testutils'; +import SeamlessAuth from '../'; + +stuff.waitUntilReady = () => SeamlessAuth(stuff.PouchDB); + +stuff.cleanup = async function () { + await new stuff.PouchDB('_users').destroy(); +} + +module.exports = stuff; From 28ee8d3f90bd512856f0130dabe379bfe432df02 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Thu, 14 Jan 2016 17:52:15 +0100 Subject: [PATCH 06/14] chore(package): update dependencies http://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0327478c..93ae3f82 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "author": "Marten de Vries", "dependencies": { "pouchdb-promise": "^0.0.0", - "extend": "^1.2.1", + "extend": "^3.0.0", "promise-nodify": "^1.0.0", "pouchdb-auth": "^2.0.0" }, From 0c335dcc0b970a02edf8167c25ba3be1f69b5834 Mon Sep 17 00:00:00 2001 From: Marten de Vries Date: Fri, 15 Jan 2016 17:34:07 +0100 Subject: [PATCH 07/14] 1.0.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 93ae3f82..f9ba6600 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pouchdb-seamless-auth", - "version": "1.0.3", + "version": "1.0.4", "main": "index.js", "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", "repository": { From 370fedbab5a1825a56cbb326cdcce06f23692ef4 Mon Sep 17 00:00:00 2001 From: greenkeeperio-bot Date: Sun, 14 Feb 2016 23:31:37 +0100 Subject: [PATCH 08/14] chore(package): update pouchdb-plugin-helper to version 3.0.0 http://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f9ba6600..36c99f6d 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "pouchdb-auth": "^2.0.0" }, "devDependencies": { - "pouchdb-plugin-helper": "^2.0.1" + "pouchdb-plugin-helper": "^3.0.0" }, "scripts": { "helper": "./node_modules/.bin/pouchdb-plugin-helper", From c258d10825d725e3857226861cbc80b34ef5c13a Mon Sep 17 00:00:00 2001 From: Linus G Thiel Date: Wed, 14 Jun 2017 11:32:28 +0000 Subject: [PATCH 09/14] Allow setting a custom local auth db Instead of relying on a default `_users` PouchDB for local auth, allow setting a custom one. This can be useful for using together with e.g. crypto-pouch, for having a per-user encrypted auth db. --- index.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/index.js b/index.js index cfeada3e..29bfdd86 100644 --- a/index.js +++ b/index.js @@ -43,6 +43,21 @@ function invalidateCache(passthrough) { } var api = {}; +api.setSeamlessAuthLocalDB = function (localDB, callback) { + local = localDB; + + var promise = Auth.useAsAuthenticationDB.call(local) + .then(invalidateCache); + + nodify(promise, callback); + return promise; +}; + +api.unsetSeamlessAuthLocalDB = function () { + local = undefined; + invalidateCache(); +}; + api.setSeamlessAuthRemoteDB = function (remoteName, remoteOptions, callback) { remote = new PouchDB(remoteName, remoteOptions); From 496679b62af4eb6e67ed142c46080948ed5a7202 Mon Sep 17 00:00:00 2001 From: Linus G Thiel Date: Fri, 16 Jun 2017 14:54:43 +0000 Subject: [PATCH 10/14] Upgrade pouchdb-auth to 3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 36c99f6d..98268f8b 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "pouchdb-promise": "^0.0.0", "extend": "^3.0.0", "promise-nodify": "^1.0.0", - "pouchdb-auth": "^2.0.0" + "pouchdb-auth": "^3.0.0" }, "devDependencies": { "pouchdb-plugin-helper": "^3.0.0" From 51ca0a582fc261ada1b769a98812195fc38bc2ef Mon Sep 17 00:00:00 2001 From: Linus G Thiel Date: Fri, 16 Jun 2017 14:54:52 +0000 Subject: [PATCH 11/14] 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98268f8b..88410540 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pouchdb-seamless-auth", - "version": "1.0.4", + "version": "2.0.0", "main": "index.js", "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", "repository": { From effc1b113ee18d820fc3a02fb1cadd9797a252d8 Mon Sep 17 00:00:00 2001 From: Linus Gustav Larsson Thiel Date: Fri, 16 Jun 2017 16:51:57 +0000 Subject: [PATCH 12/14] 2.0.1 (#31) - use pouchdb-auth 3.0.1 - compatible with pouchdb 6.x --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 88410540..73b026e4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pouchdb-seamless-auth", - "version": "2.0.0", + "version": "2.0.1", "main": "index.js", "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", "repository": { @@ -25,7 +25,7 @@ "pouchdb-promise": "^0.0.0", "extend": "^3.0.0", "promise-nodify": "^1.0.0", - "pouchdb-auth": "^3.0.0" + "pouchdb-auth": "^3.0.1" }, "devDependencies": { "pouchdb-plugin-helper": "^3.0.0" From d917681bdac686b03f0a057ed5492903c80159a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bistuer?= Date: Tue, 23 Jan 2018 02:04:10 +0700 Subject: [PATCH 13/14] Adjust pouchdb-seamless-auth for the monorepo. --- .../pouchdb-seamless-auth/.gitignore | 3 -- .../pouchdb-seamless-auth/.travis.yml | 30 ------------------- .../pouchdb-seamless-auth/{ => lib}/index.js | 0 .../pouchdb-seamless-auth/package.json | 19 ++---------- .../pouchdb-seamless-auth}/features.js | 0 .../pouchdb-seamless-auth}/signatures.js | 0 .../pouchdb-seamless-auth}/utils.js | 0 7 files changed, 2 insertions(+), 50 deletions(-) delete mode 100644 packages/node_modules/pouchdb-seamless-auth/.gitignore delete mode 100644 packages/node_modules/pouchdb-seamless-auth/.travis.yml rename packages/node_modules/pouchdb-seamless-auth/{ => lib}/index.js (100%) rename {packages/node_modules/pouchdb-seamless-auth/test => tests/pouchdb-seamless-auth}/features.js (100%) rename {packages/node_modules/pouchdb-seamless-auth/test => tests/pouchdb-seamless-auth}/signatures.js (100%) rename {packages/node_modules/pouchdb-seamless-auth/test => tests/pouchdb-seamless-auth}/utils.js (100%) diff --git a/packages/node_modules/pouchdb-seamless-auth/.gitignore b/packages/node_modules/pouchdb-seamless-auth/.gitignore deleted file mode 100644 index 0e75fe55..00000000 --- a/packages/node_modules/pouchdb-seamless-auth/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -node_modules -dist -coverage diff --git a/packages/node_modules/pouchdb-seamless-auth/.travis.yml b/packages/node_modules/pouchdb-seamless-auth/.travis.yml deleted file mode 100644 index 4a63e93e..00000000 --- a/packages/node_modules/pouchdb-seamless-auth/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -sudo: false -language: node_js - -cache: - directories: - - node_modules - -node_js: - - "0.10" - -services: - - couchdb - -before_install: - - npm i -g npm@^2.0.0 - -before_script: - - npm prune - -script: npm run $COMMAND - -env: - matrix: - - COMMAND='helper -- lint' - - COMMAND='helper -- js-test' - - COMMAND='build' - -#after_success: -# - npm run helper -- semantic-release - diff --git a/packages/node_modules/pouchdb-seamless-auth/index.js b/packages/node_modules/pouchdb-seamless-auth/lib/index.js similarity index 100% rename from packages/node_modules/pouchdb-seamless-auth/index.js rename to packages/node_modules/pouchdb-seamless-auth/lib/index.js diff --git a/packages/node_modules/pouchdb-seamless-auth/package.json b/packages/node_modules/pouchdb-seamless-auth/package.json index 73b026e4..bcf6ef59 100644 --- a/packages/node_modules/pouchdb-seamless-auth/package.json +++ b/packages/node_modules/pouchdb-seamless-auth/package.json @@ -1,11 +1,9 @@ { "name": "pouchdb-seamless-auth", - "version": "2.0.1", - "main": "index.js", "description": "Seamless switching between online (CouchDB) and offline (PouchDB) authentication.", "repository": { "type": "git", - "url": "https://github.com/marten-de-vries/pouchdb-seamless-auth.git" + "url": "https://github.com/pouchdb/pouchdb-server.git" }, "keywords": [ "pouch", @@ -21,18 +19,5 @@ ], "license": "Apache-2.0", "author": "Marten de Vries", - "dependencies": { - "pouchdb-promise": "^0.0.0", - "extend": "^3.0.0", - "promise-nodify": "^1.0.0", - "pouchdb-auth": "^3.0.1" - }, - "devDependencies": { - "pouchdb-plugin-helper": "^3.0.0" - }, - "scripts": { - "helper": "./node_modules/.bin/pouchdb-plugin-helper", - "test": "npm run helper -- test", - "build": "npm run helper -- build SeamlessAuth" - } + "main": "lib/index.js" } diff --git a/packages/node_modules/pouchdb-seamless-auth/test/features.js b/tests/pouchdb-seamless-auth/features.js similarity index 100% rename from packages/node_modules/pouchdb-seamless-auth/test/features.js rename to tests/pouchdb-seamless-auth/features.js diff --git a/packages/node_modules/pouchdb-seamless-auth/test/signatures.js b/tests/pouchdb-seamless-auth/signatures.js similarity index 100% rename from packages/node_modules/pouchdb-seamless-auth/test/signatures.js rename to tests/pouchdb-seamless-auth/signatures.js diff --git a/packages/node_modules/pouchdb-seamless-auth/test/utils.js b/tests/pouchdb-seamless-auth/utils.js similarity index 100% rename from packages/node_modules/pouchdb-seamless-auth/test/utils.js rename to tests/pouchdb-seamless-auth/utils.js From 3ac8c7634aad60ad8409679ae650ac266dbe6570 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Bistuer?= Date: Tue, 23 Jan 2018 02:11:01 +0700 Subject: [PATCH 14/14] Drop some ES6 features from pouchdb-seamless-auth to match the rest of the monorepo. --- tests/pouchdb-seamless-auth/features.js | 129 ++++++++++++---------- tests/pouchdb-seamless-auth/signatures.js | 3 +- tests/pouchdb-seamless-auth/utils.js | 10 +- 3 files changed, 80 insertions(+), 62 deletions(-) diff --git a/tests/pouchdb-seamless-auth/features.js b/tests/pouchdb-seamless-auth/features.js index 00498eae..ce7f083c 100644 --- a/tests/pouchdb-seamless-auth/features.js +++ b/tests/pouchdb-seamless-auth/features.js @@ -1,4 +1,4 @@ -import {waitUntilReady, cleanup, PouchDB, should, BASE_URL, HTTP_AUTH} from './utils'; +const {waitUntilReady, cleanup, PouchDB, should, BASE_URL, HTTP_AUTH} = require('./utils'); const url = BASE_URL + '/_users'; @@ -6,72 +6,89 @@ describe('sync seamless auth tests without remote', () => { before(waitUntilReady); afterEach(cleanup); - it('test', async () => { - const resp = await PouchDB.seamlessSignUp('username', 'password'); - resp.ok.should.be.ok; - const s = await PouchDB.seamlessSession(); - s.info.authentication_db.should.equal('_users'); - should.equal(s.userCtx.name, null); - (await PouchDB.seamlessLogIn('username', 'password')).name.should.equal('username'); - (await PouchDB.seamlessLogOut()).ok.should.be.ok; + it('test', () => { + return PouchDB.seamlessSignUp('username', 'password') + .then((resp) => resp.ok.should.be.ok) + .then(() => PouchDB.seamlessSession()) + .then((resp) => { + resp.info.authentication_db.should.equal('_users'); + should.equal(resp.userCtx.name, null); + }) + .then(() => PouchDB.seamlessLogIn('username', 'password')) + .then((resp) => resp.name.should.equal('username')) + .then(() => PouchDB.seamlessLogOut()) + .then((resp) => resp.ok.should.be.ok); }); }); describe('sync seamless auth tests with remote', () => { let remoteDB, localDB; before(waitUntilReady); - beforeEach(async () => { - await PouchDB.setSeamlessAuthRemoteDB(url, {auth: HTTP_AUTH}); - remoteDB = new PouchDB(url, {auth: HTTP_AUTH}); - localDB = new PouchDB('_users'); + beforeEach(() => { + return PouchDB.setSeamlessAuthRemoteDB(url, {auth: HTTP_AUTH}) + .then(() => { + remoteDB = new PouchDB(url, {auth: HTTP_AUTH}); + localDB = new PouchDB('_users'); + }); }); - afterEach(async () => { + afterEach(() => { // local - await cleanup(); - // remote - PouchDB.unsetSeamlessAuthRemoteDB() - try { - await remoteDB.remove(await remoteDB.get('org.couchdb.user:username')); - } catch (err) {/* already not there apparently*/} + return cleanup() + .then(() => { + // remote + PouchDB.unsetSeamlessAuthRemoteDB(); + return remoteDB.get('org.couchdb.user:username') + .then((db) => remoteDB.remove(db)) + .catch(() => { /* already not there apparently */ }); + }); }); - it('test', async () => { - const resp = await PouchDB.seamlessSignUp('username', 'password'); - resp.ok.should.be.ok; + it('test', () => { + return PouchDB.seamlessSignUp('username', 'password') + .then((resp) => { + resp.ok.should.be.ok; - // check replication from remote to local - let doc; - // ethernal loop when the test doesn't pass - do { - try { - doc = await localDB.get(resp.id); - } catch (err) {/* document not yet replicated */} - } while (!doc); + function localGet() { + return localDB.get(resp.id) + // document not yet replicated + .catch(localGet); + } - // check if online session - (await PouchDB.seamlessLogIn('username', 'password')).name.should.equal('username'); - const s = await PouchDB.seamlessSession(); - s.info.authentication_handlers.should.contain('cookie'); + return localGet() + .then((doc) => { + // check if online session + return PouchDB.seamlessLogIn('username', 'password') + .then((resp) => resp.name.should.equal('username')) - // update the local document and check if replicated back - doc.abc = 1; - localDB.put(doc); + .then(() => PouchDB.seamlessSession()) + .then((resp) => resp.info.authentication_handlers.should.contain('cookie')) - // triggers the replication - PouchDB.invalidateSeamlessAuthCache(); - await PouchDB.seamlessSession(); + // update the local document and check if replicated back + .then(() => { + doc.abc = 1; + return localDB.put(doc); + }); + }) - let remoteDoc; - do { - remoteDoc = await remoteDB.get(resp.id); - } while(!remoteDoc.abc); + // triggers the replication + .then(() => { + PouchDB.invalidateSeamlessAuthCache(); + return PouchDB.seamlessSession(); + }) - // test caching code - await PouchDB.seamlessSession(); - await PouchDB.seamlessSession(); + .then(function remoteGet() { + return remoteDB.get(resp.id) + .catch(remoteGet); + }) - // log out - (await PouchDB.seamlessLogOut()).ok.should.be.ok; + // test caching code + .then(() => PouchDB.seamlessSession()) + .then(() => PouchDB.seamlessSession()) + + // log out + .then(() => PouchDB.seamlessLogOut()) + .then((resp) => resp.ok.should.be.ok); + }); }); }); @@ -79,11 +96,11 @@ describe('async seamless auth tests', () => { before(waitUntilReady); afterEach(cleanup); - it('set remote db', done => { - PouchDB.setSeamlessAuthRemoteDB(url, {auth: HTTP_AUTH}, (err, resp) => { - should.not.exist(resp); - should.not.exist(PouchDB.unsetSeamlessAuthRemoteDB()); - done(err); - }); + it('set remote db', () => { + return PouchDB.setSeamlessAuthRemoteDB(url, {auth: HTTP_AUTH}) + .then((resp) => { + should.not.exist(resp); + should.not.exist(PouchDB.unsetSeamlessAuthRemoteDB()); + }); }); }); diff --git a/tests/pouchdb-seamless-auth/signatures.js b/tests/pouchdb-seamless-auth/signatures.js index 51174abc..5490665c 100644 --- a/tests/pouchdb-seamless-auth/signatures.js +++ b/tests/pouchdb-seamless-auth/signatures.js @@ -1,4 +1,4 @@ -import {waitUntilReady, cleanup, PouchDB} from './utils'; +const {waitUntilReady, cleanup, PouchDB} = require('./utils'); describe('signatures', () => { before(waitUntilReady); @@ -8,5 +8,6 @@ describe('signatures', () => { const promise = PouchDB.seamlessSession(() => {}); promise.then.should.be.ok; promise.catch.should.be.ok; + return promise; }); }); diff --git a/tests/pouchdb-seamless-auth/utils.js b/tests/pouchdb-seamless-auth/utils.js index b68d3bf8..386198a0 100644 --- a/tests/pouchdb-seamless-auth/utils.js +++ b/tests/pouchdb-seamless-auth/utils.js @@ -1,10 +1,10 @@ -import stuff from 'pouchdb-plugin-helper/testutils'; -import SeamlessAuth from '../'; +const stuff = require('pouchdb-plugin-helper/testutils'); +const SeamlessAuth = require('../../packages/node_modules/pouchdb-seamless-auth'); stuff.waitUntilReady = () => SeamlessAuth(stuff.PouchDB); -stuff.cleanup = async function () { - await new stuff.PouchDB('_users').destroy(); -} +stuff.cleanup = () => { + return new stuff.PouchDB('_users').destroy(); +}; module.exports = stuff;