mikemintz / rethinkdb-websocket-server

Node.js WebSocket server that proxies to RethinkDB. Supports query validation.
MIT License
156 stars 22 forks source link

using server only session data in filter #29

Open Rohithzr opened 7 years ago

Rohithzr commented 7 years ago

I have a situation where the user sends a token from client via query params and I use the same to validate the session and store the the userId in the RP session.

options.sessionCreator = function (params) {
  let token = params.token;
  let user = params.user;
  if (!token || token == "" || !user || user == "") {
    return Promise.reject('Invalid auth token');
  } else {
    // use teade to validate the user from user service
    const clients = {
      users: {
        host: process.env.SERVICE_RPC_HOST,
        port: process.env.CXI_USER_PORT
      }
    }
    const data = {
      token: token,
      user: user
    }
    const authenticator = require('./middlewares/authenticator');

    return Promise.promisify(authenticator.auth)(clients, data)
      .then(function(result){
        return Promise.resolve({userId: result.data.id});
      }).catch(function(err){
        return Promise.reject(err.message);
    })
  }
};

now I want to add this userId in the filter of a query but I dont have this id in the frontend.

So I am looking for a way to either

  1. add a filter to the query on the server (maybe in validate) and not send the aforementioned filter from frontend
  2. modify the filter data on the server no matter what is sent from the front end.
// whitelisted query
r.table("trades").orderBy({index: allowSpecificFieldOrderBy(RP, "datetime")})
            .filter(r.row("currency").eq(allowAnyString(RP)))
            .filter(r.row("isExecuted").eq(true))
            .filter(r.row('userId').eq(
                 /* what can I use here? */
             ))
            .pluck("datetime", "rate", "id")
            .changes({"includeInitial": true}).opt("db", r.db("cxihub"))
            .validate(function (refs, session) {
                // console.log(refs, session)
                // { userId: '' } { userId: 1 }
                return true;
            })
mikemintz commented 7 years ago

I think you want something like this:

// whitelisted query
r.table("trades").orderBy({index: allowSpecificFieldOrderBy(RP, "datetime")})
            .filter(r.row("currency").eq(allowAnyString(RP)))
            .filter(r.row("isExecuted").eq(true))
            .filter(r.row('userId').eq(RP.ref('userId'))
            .pluck("datetime", "rate", "id")
            .changes({"includeInitial": true}).opt("db", r.db("cxihub"))
            .validate(function (refs, session) {
                return refs.userId === session.userId;
            })
Rohithzr commented 7 years ago

@mikemintz hello, thank you for your reply, the issue is that I do not have this userId on the frontend, so I send a token and it gives me userId inside session. I want to modify the incomining query to use it.

so my frontend sends {userId: "token"} while what rethinkdb sees {userId: "abcd"}

Rohithzr commented 7 years ago

I have been playing a lot with the lbrary, I can see it converts data to binary buffer and sends to rethinkdb, I tried to interept that buffer, converted to string and replaced it to my desired value and then forwarded it, but it does not work, the connection just hangs.

so I have been trying to find a suitable place in the library to modify the query beforeit is sent to the rethinkdb

mikemintz commented 7 years ago

This is not currently possible without modifying the library, but it is one of the goals of https://github.com/mikemintz/rethinkdb-websocket-server/issues/2.

One approach would be to refactor validateQueryCmd, so that instead of returning a boolean, it returns one two response types: like {type: "passthrough", allow: false/true} and {type: "rewrite", newQueryCmdBuf: ...}. You'd have to thread that through. And then you'd either refactor the API so that validate can return a rewritten query in addition to returning a boolean, or make a new API method like RP.rewrite.

I haven't fully thought this through, but I'm definitely open to ideas on refactoring so query rewriting is supported.

Rohithzr commented 7 years ago

Hello I have been trying to play with the code, find a workaround. I actually thought i succeded but that was not the case. look at this file https://github.com/Rohithzr/rethinkdb-ws-server/blob/077f41d31c97779d6f04d4c19445dbdae6ef2ffc/src/Connection.js#L127 and readme (of the idea, i tried to apply) https://github.com/Rohithzr/rethinkdb-ws-server

mikemintz commented 7 years ago

Rather than doing string manipulations like rawQuery.indexOf and rawQuery.replace, I would recommend manipulating the query as JSON using JSON.parse and JSON.stringify. I would also run validateQueryCmd before doing the query manipulation, so that you guarantee you're only manipulating a valid query.

mikemintz commented 7 years ago

You may also want to read through https://www.rethinkdb.com/docs/writing-drivers/ to get an idea of how the JSON is formatted, so it's more clear what part of the query you should manipulate.