From 242231eb2b8a0d152253fdd6a2eadf218581e095 Mon Sep 17 00:00:00 2001 From: "Didier Villevalois (Ptitjes)" Date: Wed, 22 Nov 2017 18:30:45 +0100 Subject: [PATCH] fix(ajax): correctly handle Basic authentication Fixes #109. When username and password are present in db url, generate Basic authentication token and put it in ajax request headers. --- package.json | 1 + src/admins.js | 5 ++++- src/authentication.js | 6 ++++-- src/users.js | 7 ++++++- src/utils.js | 22 +++++++++++++++++++++- test/test.issue.109.js | 18 ++++++++++++++---- 6 files changed, 50 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 4c6ac02..2118e79 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "dependencies": { "inherits": "2.0.3", "pouchdb-ajax": "6.3.4", + "pouchdb-binary-utils": "6.3.4", "pouchdb-promise": "6.3.4", "pouchdb-utils": "6.3.4", "url-join": "2.0.2", diff --git a/src/admins.js b/src/admins.js index 96108e9..7e3a8ec 100644 --- a/src/admins.js +++ b/src/admins.js @@ -1,4 +1,4 @@ -import { AuthError, getBaseUrl, getConfigUrl, wrapError } from './utils'; +import { AuthError, getBaseUrl, getBasicAuthHeaders, getConfigUrl, wrapError } from './utils'; import ajaxCore from 'pouchdb-ajax'; import { assign, toPromise } from 'pouchdb-utils'; @@ -14,6 +14,7 @@ var getMembership = toPromise(function (opts, callback) { var ajaxOpts = assign({ method: 'GET', url: url, + headers: getBasicAuthHeaders(db), }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); }); @@ -46,6 +47,7 @@ var signUpAdmin = toPromise(function (username, password, opts, callback) { method: 'PUT', url: url, processData: false, + headers: getBasicAuthHeaders(db), body: '"' + password + '"', }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); @@ -77,6 +79,7 @@ var deleteAdmin = toPromise(function (username, opts, callback) { method: 'DELETE', url: url, processData: false, + headers: getBasicAuthHeaders(db), }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); }); diff --git a/src/authentication.js b/src/authentication.js index b7e4ba6..f21e40b 100644 --- a/src/authentication.js +++ b/src/authentication.js @@ -1,6 +1,6 @@ 'use strict'; -import { AuthError, getSessionUrl, wrapError } from './utils'; +import { AuthError, getBasicAuthHeaders, getSessionUrl, wrapError } from './utils'; import ajaxCore from 'pouchdb-ajax'; import { assign, toPromise } from 'pouchdb-utils'; @@ -24,7 +24,7 @@ var logIn = toPromise(function (username, password, opts, callback) { var ajaxOpts = assign({ method: 'POST', url: getSessionUrl(db), - headers: {'Content-Type': 'application/json'}, + headers: assign({'Content-Type': 'application/json'}, getBasicAuthHeaders(db)), body: {name: username, password: password}, }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); @@ -39,6 +39,7 @@ var logOut = toPromise(function (opts, callback) { var ajaxOpts = assign({ method: 'DELETE', url: getSessionUrl(db), + headers: getBasicAuthHeaders(db), }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); }); @@ -54,6 +55,7 @@ var getSession = toPromise(function (opts, callback) { var ajaxOpts = assign({ method: 'GET', url: url, + headers: getBasicAuthHeaders(db), }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); }); diff --git a/src/users.js b/src/users.js index f3e1c06..af15c06 100644 --- a/src/users.js +++ b/src/users.js @@ -1,6 +1,6 @@ 'use strict'; -import { AuthError, getUsersUrl, wrapError } from './utils'; +import { AuthError, getBasicAuthHeaders, getUsersUrl, wrapError } from './utils'; import Promise from 'pouchdb-promise'; import ajaxCore from 'pouchdb-ajax'; @@ -43,6 +43,7 @@ function updateUser(db, user, opts, callback) { method: 'PUT', url: url, body: user, + headers: getBasicAuthHeaders(db), }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); } @@ -89,6 +90,7 @@ var getUser = toPromise(function (username, opts, callback) { var ajaxOpts = assign({ method: 'GET', url: url + '/' + encodeURIComponent('org.couchdb.user:' + username), + headers: getBasicAuthHeaders(db), }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); }); @@ -137,6 +139,7 @@ var deleteUser = toPromise(function (username, opts, callback) { var ajaxOpts = assign({ method: 'DELETE', url: url, + headers: getBasicAuthHeaders(db), }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); }); @@ -169,6 +172,7 @@ var changePassword = toPromise(function (username, password, opts, callback) { var ajaxOpts = assign({ method: 'PUT', url: url, + headers: getBasicAuthHeaders(db), body: user, }, opts.ajax || {}); ajaxCore(ajaxOpts, wrapError(callback)); @@ -193,6 +197,7 @@ var changeUsername = toPromise(function (oldUsername, newUsername, opts, callbac var updateOpts = assign({ method: 'PUT', url: url, + headers: getBasicAuthHeaders(db), body: user, }, opts.ajax); return ajax(updateOpts); diff --git a/src/utils.js b/src/utils.js index b673908..b9bbc6f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -3,6 +3,7 @@ import urlJoin from 'url-join'; import urlParse from 'url-parse'; import inherits from 'inherits'; +import { btoa } from 'pouchdb-binary-utils'; function getBaseUrl(db) { if (typeof db.getUrl === 'function') { // pouchdb pre-6.0.0 @@ -26,6 +27,17 @@ function getSessionUrl(db) { return urlJoin(getBaseUrl(db), '/_session'); } +function getBasicAuthHeaders(db) { + var url = urlParse(db.name); + if (!url.auth) { + return {}; + } + + var str = url.username + ':' + url.password; + var token = btoa(unescape(encodeURIComponent(str))); + return {Authorization: 'Basic ' + token}; +} + function wrapError(callback) { // provide more helpful error message return function (err, res) { @@ -51,4 +63,12 @@ function AuthError(message) { inherits(AuthError, Error); -export { AuthError, getBaseUrl, getConfigUrl, getSessionUrl, getUsersUrl, wrapError }; +export { + AuthError, + getBaseUrl, + getBasicAuthHeaders, + getConfigUrl, + getSessionUrl, + getUsersUrl, + wrapError, +}; diff --git a/test/test.issue.109.js b/test/test.issue.109.js index 5940da9..1c5c751 100644 --- a/test/test.issue.109.js +++ b/test/test.issue.109.js @@ -4,6 +4,7 @@ var PouchDB = require('pouchdb-memory'); var Authentication = require('../lib'); PouchDB.plugin(Authentication); +var utils = require('./test-utils'); var chai = require('chai'); chai.should(); @@ -14,16 +15,25 @@ describe('issue-109', function () { var db; beforeEach(function () { + + db = new PouchDB(dbName); - return db.signUpAdmin('anna', 'secret').then(function () { + return utils.ensureUsersDatabaseExists(db).then(function () { + return db.signUpAdmin('anna', 'secret'); + }).then(function () { return db.signUp('spiderman', 'will-forget'); }); }); + afterEach(function () { return db.logIn('anna', 'secret').then(function () { return db.deleteUser('spiderman'); }).then(function () { return db.deleteAdmin('anna'); + }).then(function () { + return db.logOut(); + }).then(function () { + return db.destroy(); }); }); @@ -41,9 +51,9 @@ describe('issue-109', function () { }); }); - // Blocked by #109 - it.skip('Test admin change user password with basic authentication', function () { - var dbWithBasicAuth = new PouchDB(dbName.replace('http://', 'http://anna:secret@')); + it('Test admin change user password with basic authentication', function () { + var dbNameWithAuth = dbName.replace('http://', 'http://anna:secret@'); + var dbWithBasicAuth = new PouchDB(dbNameWithAuth, {skip_setup: true}); return dbWithBasicAuth.changePassword('spiderman', 'will-remember').then(function (res) { res.ok.should.equal(true); }).then(function () {