diff --git a/package-lock.json b/package-lock.json index f50eaadb..0fa6aeb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "pouchdb-adapter-http": "^7.2.2", "pouchdb-core": "^7.2.2", "pouchdb-mapreduce": "^7.2.2", + "pouchdb-session-authentication": "^1.2.0", "properties": "^1.2.1", "queue-promise": "^2.2.1", "readline-sync": "^1.4.10", @@ -16125,6 +16126,58 @@ "uuid": "bin/uuid" } }, + "node_modules/pouchdb-session-authentication": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pouchdb-session-authentication/-/pouchdb-session-authentication-1.2.0.tgz", + "integrity": "sha512-jfF1J50JvhIFx9pcI3Bxi6G3ppmuraPd9wj/ojNIh0nw//P5F44NDnrLQjOu25EqCEN8y+GrP+zC+XpZVANW2w==", + "dependencies": { + "pouchdb-fetch": "^8.0.1" + }, + "engines": { + "node": ">=16.12.0", + "npm": ">=8.3.1" + } + }, + "node_modules/pouchdb-session-authentication/node_modules/fetch-cookie": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", + "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", + "dependencies": { + "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pouchdb-session-authentication/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/pouchdb-session-authentication/node_modules/pouchdb-fetch": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/pouchdb-fetch/-/pouchdb-fetch-8.0.1.tgz", + "integrity": "sha512-Px5HLT8MxqTujc8bpPRKoouznDTJa9XBGqCbhl95q6rhjWRfwZEvXjV92z0B5BALAM6D6avMyG0DjuNfUWnMuA==", + "dependencies": { + "abort-controller": "3.0.0", + "fetch-cookie": "0.11.0", + "node-fetch": "2.6.7" + } + }, "node_modules/pouchdb-show": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pouchdb-show/-/pouchdb-show-4.2.0.tgz", @@ -33325,6 +33378,42 @@ } } }, + "pouchdb-session-authentication": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pouchdb-session-authentication/-/pouchdb-session-authentication-1.2.0.tgz", + "integrity": "sha512-jfF1J50JvhIFx9pcI3Bxi6G3ppmuraPd9wj/ojNIh0nw//P5F44NDnrLQjOu25EqCEN8y+GrP+zC+XpZVANW2w==", + "requires": { + "pouchdb-fetch": "^8.0.1" + }, + "dependencies": { + "fetch-cookie": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", + "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", + "requires": { + "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" + } + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "pouchdb-fetch": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/pouchdb-fetch/-/pouchdb-fetch-8.0.1.tgz", + "integrity": "sha512-Px5HLT8MxqTujc8bpPRKoouznDTJa9XBGqCbhl95q6rhjWRfwZEvXjV92z0B5BALAM6D6avMyG0DjuNfUWnMuA==", + "requires": { + "abort-controller": "3.0.0", + "fetch-cookie": "0.11.0", + "node-fetch": "2.6.7" + } + } + } + }, "pouchdb-show": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pouchdb-show/-/pouchdb-show-4.2.0.tgz", diff --git a/package.json b/package.json index e5ce7782..4f90f08f 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "pouchdb-adapter-http": "^7.2.2", "pouchdb-core": "^7.2.2", "pouchdb-mapreduce": "^7.2.2", + "pouchdb-session-authentication": "^1.2.0", "properties": "^1.2.1", "queue-promise": "^2.2.1", "readline-sync": "^1.4.10", diff --git a/src/lib/api.js b/src/lib/api.js index 53e42af0..0d74ef14 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -7,6 +7,7 @@ const log = require('./log'); const url = require('url'); const cache = new Map(); +const sessionCookieName = 'AuthSession'; // Helper function to create request headers with session token (if available) const withSessionCookie = (...args) => { @@ -19,7 +20,11 @@ const withSessionCookie = (...args) => { const sessionToken = environment.sessionToken; if (sessionToken || options.headers) { - options.headers = Object.assign({}, options.headers || {}, { Cookie: sessionToken }); + options.headers = Object.assign( + {}, + options.headers || {}, + { Cookie: `${sessionCookieName}=${sessionToken}` } + ); } return options; diff --git a/src/lib/db.js b/src/lib/db.js index 03a8e6a5..cf9baaac 100644 --- a/src/lib/db.js +++ b/src/lib/db.js @@ -1,37 +1,11 @@ -const { Headers } = require('cross-fetch'); const PouchDB = require('pouchdb-core'); PouchDB.plugin(require('pouchdb-adapter-http')); PouchDB.plugin(require('pouchdb-mapreduce')); +PouchDB.plugin(require('pouchdb-session-authentication')); const ArchivingDB = require('./archiving-db'); const environment = require('./environment'); -const sessionCookieAwareFetch = () => (url, opts = {}) => { - const sessionToken = environment.sessionToken; - - if (sessionToken) { - const setHeader = (headers, name, value) => { - if (headers instanceof Headers) { - headers.set(name, value); - } else if (Array.isArray(headers)) { - headers.push([name, value]); - } else if (typeof headers === 'object') { - headers[name] = value; - } - }; - - // Ensure opts.headers exists - if (!opts.headers) { - opts.headers = new Headers(); - } - - // Set the 'Cookie' header - setHeader(opts.headers, 'Cookie', sessionToken); - } - - return PouchDB.fetch(url, opts); -}; - module.exports = () => { if (environment.isArchiveMode) { return new ArchivingDB(environment.archiveDestination); @@ -39,6 +13,6 @@ module.exports = () => { return new PouchDB(environment.apiUrl, { ajax: { timeout: 60000 }, - fetch: sessionCookieAwareFetch(), + session: environment.sessionToken, }); }; diff --git a/test/lib/db.spec.js b/test/lib/db.spec.js deleted file mode 100644 index d2e6ed1f..00000000 --- a/test/lib/db.spec.js +++ /dev/null @@ -1,52 +0,0 @@ -const { expect } = require('chai'); -const { Headers } = require('cross-fetch'); -const sinon = require('sinon'); -const rewire = require('rewire'); - -const db = rewire('../../src/lib/db'); -const environment = require('../../src/lib/environment'); - -describe('PouchDB', () => { - describe('authentication with session cookie', () => { - let sessionCookieAwareFetch; - const sessionToken = 'sessionTokenValue'; - - beforeEach(() => { - sinon.stub(environment, 'isArchiveMode').get(() => false); - sinon.stub(environment, 'sessionToken').get(() => sessionToken); - sinon.stub(environment, 'apiUrl').get(() => 'http://example.com/db-name'); - - sessionCookieAwareFetch = db.__get__('sessionCookieAwareFetch'); - }); - - afterEach(() => { - sinon.restore(); - }); - - it('should include session token in PouchDB fetch headers(Headers) if available', async () => { - const fetch = sessionCookieAwareFetch(); - const options = { headers: new Headers() }; - - await fetch('http://example.com/db-name', options); - expect(options.headers.get('Cookie')).to.contains(sessionToken); - }); - - it('should include session token in PouchDB fetch headers(object) if available', async () => { - const fetch = sessionCookieAwareFetch(); - const options = { headers: {} }; - - await fetch('http://example.com/db-name', options); - expect(options.headers.Cookie).to.contains(sessionToken); - }); - - it('should not include session token in PouchDB fetch headers if not available', async () => { - sinon.stub(environment, 'sessionToken').get(() => undefined); - - const fetch = sessionCookieAwareFetch(); - const options = { headers: new Headers() }; - - await fetch('http://example.com/db-name', options); - expect(options.headers.get('Cookie')).to.be.empty; - }); - }); -});