Travis Klein
Travis Klein

Reputation: 85

pouchdb-authentication how do I set roles for a new user

I want to set roles for a new user.

I tried updating roles array in metadata during signup but I get an error. If I remove the roles metadata new user is created just fine.

db.signUp(userId, 'pass', {
    metadata: {
      email: '[email protected]',
      birthday: '1932-03-27T00:00:00.000Z',
      likes: ['acrobatics', 'short pants', 'sidekickin\'']
      roles: ['basic']
    }
  }, function (err, response) {
    if (err) {
      if (err.name === 'conflict') {
        console.log('batman" already exists, choose another username')
        // "batman" already exists, choose another username
      } else if (err.name === 'forbidden') {
        console.log('invalid username')
        // invalid username
      } else {
        console.log('sign up error')
        // HTTP error, cosmic rays, etc.
      }
    } else {
      console.log('user signed up')
     // login()
    }
  })

So I figured it out first modify the pouchdb-authentication index.js code to accept roles.

var signUp = pouchdbUtils.toPromise(function (username, password,roles, opts, callback) {
  var db = this;
  if (typeof callback === 'undefined') {
    callback = typeof opts === 'undefined' ? (typeof password === 'undefined' ?
      username : password) : opts;
    opts = {};
  }
  if (['http', 'https'].indexOf(db.type()) === -1) {
    return callback(new AuthError('This plugin only works for the http/https adapter. ' +
      'So you should use new PouchDB("http://mysi3te.org:5984/mydb") instead.'));
  } else if (!username) {
    return callback(new AuthError('You must provide a username'));
  } else if (!password) {
    return callback(new AuthError('You must provide a password'));
  }

  var userId = 'org.couchdb.user:' + username;
  var user = {
    name: username,
    password: password,
    roles: roles,
    type: 'user',
    _id: userId,
  };

  updateUser(db, user, opts, callback);
});

Then you can send the roles in the sign up. I'm sending basic below

   signUp()
function signUp () {
  db.signUp(userId, 'pass', ['basic'], {
    metadata: {
      email: '[email protected]',
      birthday: '1932-03-27T00:00:00.000Z',
      likes: ['acrobatics', 'short pants', 'sidekickin\'']
    }
  }, function (err, response) {
    if (err) {
      if (err.name === 'conflict') {
        console.log('batman" already exists, choose another username')
        // "batman" already exists, choose another username
      } else if (err.name === 'forbidden') {
        console.log('invalid username', err)
        // invalid username
      } else {
        console.log('sign up error', err)
        // HTTP error, cosmic rays, etc.
      }
    } else {
      console.log('user signed up', err)
      login()
    }
  })
}

now you have to go to couchdb _user database _design/_auth document modify

else if (newDoc.roles.length > 0 ) {\n 

set this to

else if (newDoc.roles.length > 0 && newDoc.roles[0] !== 'basic' ) {\n

Now you will have basic in your session and can add more roles my adjusting the code a bit. This allows me to set member role permissions easily to limit access to other databases. Or a simpler solution i found and tested is to add a new design doc to your database with the following code. It will only allow users that are logged in to access your database

{
  "_id": "_design/usersOnly",
  "_rev": "17-6fb7e6c0ccfca8b2e56738ad63e26107",
  "language": "javascript",
  "validate_doc_update": "\n  function(newDoc, oldDoc, userCtx){   \n // check if user is logged in \n  if(!userCtx.name){ throw({forbidden : 'No way.. login man!'});}   \n //reqired fields to update \n  function require(field){   var message = field + ' is required';  if(!newDoc[field]){  throw({'forbidden':message})  }}   require('name');                                         }"
}

Upvotes: 1

Views: 999

Answers (1)

lossleader
lossleader

Reputation: 13495

The validate function design documentation uses the _users design document as the primary example:

Example: The _design/_auth ddoc from _users database uses a validation function to ensure that documents contain some required fields and are only modified by a user with the _admin role:

        ...
        } else if (newDoc.roles.length > 0) {
            throw({forbidden: 'Only _admin may set roles'});
        }
        ...

In fauxton (for example) you can login as the couchdb admin user and go to _users database and change the design (at your own peril), for example:

        } else if (newDoc.roles.length > 0 && !("basic" === newRoles[0] && newDoc.roles.length === 1)) {
            throw({forbidden: 'Only _admin may set roles'});
        }  

saving it as you would any other document. (I say peril, since subtle accidents in this design document can potentially allow unauthorized users to drastically raise their permissions.)

With such a change, new users are allowed to be created with the basic role by couchdb, so your client code works if it sets roles correctly. In pouchdb-authenticate this seems to be with opt.roles and not opt.metadata.roles, i.e.:

db.signUp(userId, 'pass', {
    metadata: {
      email: '[email protected]',
      birthday: '1932-03-27T00:00:00.000Z',
      likes: ['acrobatics', 'short pants', 'sidekickin\'']
    },
    roles: ['basic'] }, ... )

Upvotes: 1

Related Questions