feathers-hooks-common icon indicating copy to clipboard operation
feathers-hooks-common copied to clipboard

Using fastJoin with Mongoose lean:false

Open mrfrase3 opened this issue 6 years ago • 4 comments
trafficstars

I spent quite a few hours looking into this, and after giving up, found the cause of the bug on accident. Not sure if this affects more than just fastJoin.

Steps to reproduce

Say we have a posts mongoose service, that for one reason or another, lean is disabled:

const createService = require('feathers-mongoose');
const createModel = require('../../models/posts.model');
const hooks = require('./posts.hooks');

module.exports = function (app) {
  const Model = createModel(app);
  const paginate = app.get('paginate');

  const options = {
    Model,
    paginate,
    lean: false,
  };

  app.use('posts', createService(options));
  const service = app.service('posts');
  service.hooks(hooks);
};

and in the hooks we add a fastjoin: (in this case, populating the field "author" with the createdBy user)

const { fastJoin } = require('feathers-hooks-common');

const postResolvers = {
  joins: {
    createdBy: () => async (post, context) => {
      post.author = (await context.app.service('users').find({
        query: { _id: post.createdBy },
      }))[0];
    },
  },
};

module.exports = {
  before: {
    ...
  },

  after: {
    all: [fastJoin(postResolvers)],
    find: [],
    get: [],
    create: [],
    update: [],
    patch: [],
    remove: []
  },
  ...
};

Expected behavior

The client should receive a posts object with an "author" field.

Actual behavior

The client does not receive a posts object with an "author" field.

This is because modifying the mongoose Model object will not stick when toObject is called before sending. What should be given to the resolvers is either the object returned from toObject, or the _doc field of the Model.

i.e. this will fix the issue:

const postResolvers = {
  joins: {
    createdBy: () => async (post, context) => {
      post._doc.author = (await context.app.service('users').find({
        query: { _id: post.createdBy },
      }))[0];
    },
  },
};

mrfrase3 avatar Dec 22 '18 18:12 mrfrase3

All common hooks, and the documentation, assume a disabled ORM, that is lean:true for Mongoose. You have to work around the the ORM otherwise, as you did.

Please feel free to comment or even to reopen this issue.

eddyystop avatar Dec 25 '18 20:12 eddyystop

I've reopened the issue as information for others who may run into this issue.

eddyystop avatar Dec 26 '18 13:12 eddyystop

Upon debugging a separate issue, I've found that this is also the case with discard, and I'm assuming anything that uses getItems.

Due to the common nature of the use case of hooks like discard (passwords), I feel like this is a rather large security vulnerability for those that unknowingly use lean: false to get their virtuals working...

Alternatively this is a feathersjs or feathers-mongoose issue, idk, but it wouldn't be that hard to code against though.

mrfrase3 avatar Jan 17 '19 16:01 mrfrase3

Feathers assumes lean: true is being used. You yourself have to handle any ramifications if you do otherwise.

eddyystop avatar Jan 17 '19 17:01 eddyystop