pouchdb / pouchdb-server

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

TypeError: db.info is not a function #374

Open PenguinSnail opened 5 years ago

PenguinSnail commented 5 years ago

Whenever I try creating a database or performing actions that require authentication that I don't have, instead of the server returning an unauthorized message, it never responds and I get this error:

(node:4599) UnhandledPromiseRejectionWarning: TypeError: db.info is not a function
    at /home/penguinsnail/Documents/FRC/StrangeScout/server/node_modules/express-pouchdb/lib/routes/db.js:31:10
    at /home/penguinsnail/Documents/FRC/StrangeScout/server/node_modules/promise-nodify/index.js:22:7
    at processTicksAndRejections (internal/process/next_tick.js:81:5)
(node:4599) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:4599) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:4599) UnhandledPromiseRejectionWarning: [object Object]
(node:4599) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)

However, with proper authorization no error occurs and the request completes and responds successfully.

My code is here:

const express = require('express');
const PouchDB = require('pouchdb');
const path = require('path');

// winston for logging
const winston = require('winston');
const expressWinston = require('express-winston');

// define database prefix
const db = PouchDB.defaults({prefix: path.join(__dirname, 'dbs/')})

const app = express();
const port = 80;

// listener
app.listen(port, () => console.log(`listening on port ${port}`));

// logging (https://github.com/bithavoc/express-winston#request-logging)
app.use(expressWinston.logger({
    transports: [
        new winston.transports.Console()
    ],
    format: winston.format.combine(
        winston.format.json()
    ),
    meta: false,
    msg: "HTTP {{req.method}} {{req.url}} {{req.method}} {{res.responseTime}}ms",
    expressFormat: false
}));

// static files at root
app.use('/', express.static(path.join(__dirname, 'static')));
// pouchdb-server
app.use('/db', require('express-pouchdb')(db));
benbenbenbenbenben commented 4 years ago

Looks like line 30 of express-pouchdb/lib/routes/db.js anticipates a synchronous function call for req.PouchDB.new. In reality this is a promise...

var db = req.PouchDB.new(name, utils.makeOpts(req));

I've create a pull request that I believe fixes it. #433

HiveTechDev commented 2 years ago

so, I looked @benbenbenbenbenben's implementation, and he's right. One catch, it's not ALWAYS a promise.

Using pouchdb-authentication with express-pouchdb you have a couple scenarios of users:

  1. User asking for/creating a DB without proper authorization.
    • DB is a promise, need to resolve (this is @benbenbenbenbenben's case above)
  2. User is asking for db with proper authorization
    • DB is a promise
  3. User is an ADMIN, creating a db with proper authorization. This should be successful, but if you use the above code, it doesn't work. Because the db returned is a db object, not a promise.

So, i let it resolve if it is a promise, and if its not, resolve will pass the db through anyway. My solution is as follows:

  1. Replace app.put('/:db ... with

` app.put('/:db', utils.jsonParser, function (req, res) { var name = cleanFilename(req.params.db);

    req.PouchDB.allDbs(function (err, dbs) {
        if (err) {
            return utils.sendError(res, err);
        }

        if (dbs.indexOf(name) !== -1) {
            return utils.sendJSON(res, 412, {
                'error': 'file_exists',
                'reason': 'The database could not be created.'
            });
        }

        // PouchDB.new() instead of new PouchDB() because that adds
        // authorisation logic
        var check_resolve = req.PouchDB.new(name, utils.makeOpts(req));
        Promise.resolve(check_resolve).then(function(db) {
            db.info(function (err) {
                if (err) {
                    // temoperary workaround for leveldb adapter, see
                    // https://github.com/pouchdb/pouchdb/issues/5668
                    // when removing this code, also remove mkdir
                    // from dependencies in package.json
                    if (err.name === 'OpenError') {
                        var path = db.__opts.prefix ? db.__opts.prefix + name : name;

                        mkdirp(pathResolve(path), function (err) {
                            if (err) {
                                return utils.sendError(res, err, 412);
                            }

                            db = req.PouchDB.new(name, utils.makeOpts(req));
                            db.info(function (err) {

                                if (err) {
                                    return utils.sendError(res, err, 412);
                                }
                                utils.setLocation(res, name);
                                utils.sendJSON(res, 201, {ok: true});
                            });
                        });
                        return;
                    }

                    return utils.sendError(res, err, 412);
                }
                utils.setLocation(res, name);
                utils.sendJSON(res, 201, {ok: true});
            });
        })
        .catch((err) =>  {
            console.error("err: ", err);
            return utils.sendError(res, err, 412);
        })
    });
});

`

I then used patch-package to save these changes to my project express-pouchdb. It was the easiest since this is a monorepo and hard to install via git in npm if i forked pouch-db server.

I might make a pull request but. From the looks of it, it will sit stale.

HiveTechDev commented 2 years ago

I'm also going to note, this error, should have been properly wrapped anyway. right now it will fail and the WHOLE express app will stop functioning. So, kind of problematic. i don't know why this hasn't come up or people are just not using pouchdb-authentication at all

ghost commented 2 years ago

This bug was reported Feb 2019, it's now nearly 3 years later.

I did this with CURL C:\Users\fluff>curl -X PUT localhost:26501/somedatabase curl: (56) Recv failure: Connection was reset

Server Did This C:\Users\fluff\AppData\Roaming\npm\node_modules\pouchdb-server\node_modules\express-pouchdb\lib\routes\db.js:31 db.info(function (err) { ^

TypeError: db.info is not a function

Conclusion This is all it takes to crash the server due to this bug, it's not a bug it's a VOLNURABILITY! Literally, if the database does not exist and someone tries to call it even without a username and password, boom server dies!

This software is ABANDON WEAR and should not be used because no one fixes security issues such as these in anywhere near a timely fashion!

I just wated 7 hours come find out I need to delete this and find a windows based CouchDB alternative..