pouchdb / pouchdb-server

CouchDB-compatible server built on PouchDB and Node
Apache License 2.0
944 stars 155 forks source link

Pouchdb Fauxton path mismatch via Reverse Proxy #431

Open cefn opened 4 years ago

cefn commented 4 years ago

Hi all and thanks for your work on Pouchdb! It was a really exciting discovery for me, and I am hoping to do great things!

Unfortunately, the bundled version of Fauxton still seems to suffer from https://github.com/apache/couchdb-fauxton/issues/944 meaning it cannot function when the express app is routed via a Reverse Proxy (e.g. Amazon API Gateway). Otherwise it would be perfect for my case.

Because of the incorrect resource paths from that bug, only the left bar of Fauxton appears, and none of the controls work. My pouchdb NodeJS app works when locally hosted, but not when mapped to the path /dev/ through a reverse proxy.

I would be glad of any pointers how to solve this issue the right way with the fewest hacks. See the Chrome inspector screenshot below for the mismatched URLs. image

Fauxton's logic incorrectly calculates the db resource path at / and authentication resource path at /_session causing the failures shown above. The logic doesn't take account of the mount point /dev/. Fauxton should in fact have retrieved the db resource from /dev/ and hit /dev/_session for authentication.

This is possibly because express itself thinks the root path is /, before the reverse proxy gets its hands on it and maps it to /dev/. The URL the pouchdb-server can see(through express) cannot be used by an external HTTP client.

I am happy to make the URL resource path explicit in my code if there is some way to do so. I have no choice but to use a reverse proxy for my case without a LOT of extra engineering.

FIXES OUT THERE?

Some work on the authentication plugin looks like it might have addressed the issue with _session being routed incorrectly. https://github.com/pouchdb-community/pouchdb-authentication/issues/215

However, overall mounting Pouchdb Fauxton anywhere except /_utils/ seems like an unsolved issue since the last comment on https://github.com/pouchdb/pouchdb-server/issues/260 17 Oct 2018

Is this because the fix hasn't been bundled through pouchdb-fauxton yet? Or doesn't the fix work in my case (where a reverse proxy is changing the mount point from the resource path express can see).

Alternatively perhaps there's a trivial way to work around the issue meaning noone has had a major reason to work on it. Is following https://github.com/pouchdb/pouchdb-server/issues/183#issuecomment-423965218 the right way forward?

I recall a comment about possibly adding a config property that can be set to tell pouchdb what its external root URL is, but I can't find that property.

Luckily the database endpoints themselves seem to be fine. However, key endpoints for the Fauxton SPA have incorrectly mapped URLs .

BACKGROUND - MY USE CASE

I encountered the issue when mounting pouchdb-server via aws-serverless-express on an AWS Lambda. Spent a long time trying to debug what I assumed was a Lambda event-translation, CORS or Mime Type issue. Finally found AWS API Gateway was mounting handlers via a reverse-proxy at servername.awsthingy.com/dev/.

HiveTechDev commented 2 years ago

Its kind of a shame this still hasn't been looked at. Not downing anyone's work, just seems like a non-starter for so many people using express. including my own.

cefn commented 2 years ago

For reference for my (Lambda) case a workaround is probably to create a route from a dedicated domain, so the resource paths aren't fudged. But that was the effort (and cost) I wanted to avoid given ideally I wanted to spawn multiple ephemeral DBs.

pepijndevos commented 2 years ago

This has been fixed upstream: https://github.com/apache/couchdb-fauxton/pull/1078

mfucci commented 2 years ago

I ran into the same problem and I was able to use express to "hot patch" Fauxton js (patch for pouchdb-fauxton@0.0.6):

    const databaseUrlPrefix = "/db";
    this.server.use(databaseUrlPrefix, (req, res, next) => {
        if (req.url.endsWith("_utils/dashboard.assets/js/bundle-34997e32896293a1fa5d71f79eb1b4f7.js")) {
            const jsFile = fs.readFileSync(path.join(__dirname, "../../node_modules/pouchdb-fauxton/www/dashboard.assets/js/bundle-34997e32896293a1fa5d71f79eb1b4f7.js")).toString();
            res.send(jsFile
                .replace("host:\"../..\"", "host:\"..\"")
                .replace("root:\"/_utils\"", `root:"${databaseUrlPrefix}/_utils"`)
                .replace(/url:\"\/_session/g, `url:"${databaseUrlPrefix}/_session`)
                .replace(/url:\"\/_replicator/g, `url:"${databaseUrlPrefix}/_replicator`)
                .replace(/window\.location\.origin\+\"\/_replicator/g, `window.location.origin+"${databaseUrlPrefix}/_replicator`)
                .replace(/url:\"\/_users/g, `url:"${databaseUrlPrefix}/_users`)
                .replace("window.location.origin+\"/\"+o.default.utils.safeURLName", `window.location.origin+"${databaseUrlPrefix}/"+o.default.utils.safeURLName`));
            return;
        }
        return expressPouchDB(
            PouchDB.defaults({ prefix: databasePath }),
            { 
                logPath: logFile,
            })(req, res, next);
    });

Pretty ugly, but makes it work until the upstream fix makes its way to a new pouchdb release... I haven't tested all Fauxton features, but should be pretty easy to add more "replace" to make everything works as it should.