Currently, express-pouchdb does not handle sources and targets in any form other than a url. However, CouchDB specifies three ways to provide authentication for the replication route, two of which provide source and target as objects that are unhandled, so attempting to use these alternate forms of authentication cause the PouchDB server to throw a 500 error. I fixed this by replacing the source and target with PouchDB objects generated by req.PouchDB.new, which handles these forms of authentication. Is this the right way to go about this? If so, I'll make a PR and link it here.
Reproducible setup and test:
const axios = require("axios");
const importFresh = require("import-fresh");
const btoa = require("btoa");
/**
* Creates an in-memory PouchDB server, a PouchDB object to access it, and
* expose the server on localhost:port.
*
* @param {number} port - the port at which the in-memory server should be
* made accessible.
*
* @returns {PouchDB} a PouchDB object to access the in-memory PouchDB server
*/
function pouchDBMemoryServer(username, password, port) {
// we need to disable caching of required modules to create separate pouchdb
// server instances
var InMemPouchDB = importFresh("pouchdb").defaults({
db: importFresh("memdown"),
});
const app = importFresh("express-pouchdb")(InMemPouchDB, {
inMemoryConfig: true,
});
// add admin
app.couchConfig.set("admins", username, password, () => {});
app.listen(port);
return InMemPouchDB;
}
async function testIt() {
// create two in-memory PouchDB servers
let sourcePort = 5984;
let targetPort = 5985;
let username = "username";
let password = "password";
let sourceInstance = pouchDBMemoryServer(username, password, sourcePort);
let targetInstance = pouchDBMemoryServer(username, password, targetPort);
// create a database in the source instance
let dbName = "u-test";
let db = new sourceInstance(dbName);
await db.put({ _id: "0", exampleDoc: "test" });
// create basic authorization as base64 string. Note that the _replicate route
// could also take this as { auth: { username, password } }
const authOpts = {
headers: {
Authorization: "Basic " + btoa(`${username}:${password}`),
},
};
// ensure database is present
await axios
.get(`http://localhost:${sourcePort}/${dbName}`, authOpts)
.then((r) => console.log(r.status, r.statusText, r.data));
// attempt to replicate
await axios
.post(
`http://localhost:${sourcePort}/_replicate`,
{
source: {
url: `http://localhost:${sourcePort}/_replicate/${dbName}`,
...authOpts,
},
target: {
url: `http://localhost:${targetPort}/_replicate/${dbName}`,
...authOpts,
},
create_target: true,
continuous: true,
},
authOpts
)
.then((r) => console.log(r.data))
.catch((err) => console.log(err.status));
}
await testIt();
Which throws:
> await testIt();
200 OK {
doc_count: 1,
update_seq: 1,
backend_adapter: 'MemDOWN',
db_name: 'u-test',
auto_compaction: false,
adapter: 'leveldb',
instance_start_time: '1650047291155'
}
undefined
undefined
> Error: Missing/invalid DB name
at PouchAlt.PouchDB (/home/.../node_modules/pouchdb/lib/index.js:2649:11)
at new PouchAlt (/home/.../node_modules/pouchdb/lib/index.js:2786:13)
at staticSecurityWrappers.replicate (/home/.../node_modules/pouchdb-security/lib/index.js:211:62)
at callHandlers (/home/.../node_modules/pouchdb-wrappers/lib/index.js:467:17)
at Function.replicate (/home/.../node_modules/pouchdb-wrappers/lib/index.js:428:12)
at /home/.../node_modules/express-pouchdb/lib/routes/replicate.js:38:17
at Layer.handle [as handle_request] (/home/.../node_modules/express/lib/router/layer.js:95:5)
at next (/home/.../node_modules/express/lib/router/route.js:137:13)
at /home/.../node_modules/express-pouchdb/lib/utils.js:41:7
at /home/.../node_modules/body-parser/lib/read.js:130:5
at invokeCallback (/home/.../node_modules/raw-body/index.js:224:16)
at done (/home/.../node_modules/raw-body/index.js:213:7)
at IncomingMessage.onEnd (/home/.../node_modules/raw-body/index.js:273:7)
at IncomingMessage.emit (node:events:402:35)
at IncomingMessage.emit (node:domain:537:15)
at endReadableNT (node:internal/streams/readable:1343:12)
But after applying the below diff (generated by patch-package), everything works as expected:
Currently, express-pouchdb does not handle sources and targets in any form other than a url. However, CouchDB specifies three ways to provide authentication for the replication route, two of which provide source and target as objects that are unhandled, so attempting to use these alternate forms of authentication cause the PouchDB server to throw a 500 error. I fixed this by replacing the source and target with PouchDB objects generated by req.PouchDB.new, which handles these forms of authentication. Is this the right way to go about this? If so, I'll make a PR and link it here.
Reproducible setup and test:
Which throws:
But after applying the below diff (generated by patch-package), everything works as expected:
This issue body was partially generated by patch-package.