0

In the answer at link its sugested that to keep a count of users: when a client creates a user in the promise of that function to return a transaction that updates a count.

Here is a similar snippet in firebase 3.0

the DB structure is:

- users
-- someuid
--- displayName: 'Dale'
- usersCount
-- count: 1
-- users
--- someuid : true

<script src="https://www.gstatic.com/firebasejs/3.6.1/firebase.js">

</script>
<script>
  // Initialize Firebase
  var config = {
    ..
  };
  firebase.initializeApp(config);


  function createNewAccount() {
    return firebase.auth().signInAnonymously()
      .then(createUserAccountData)
      .then(updateUser);
  }

  function updateUser() {
    console.log('update user count');
    var user = firebase.auth().currentUser;
    var ref = firebase.database().ref('/usersCount');
    var uid = user.uid;
    return ref.transaction(function(post) { 
      if(post) {
        if(post.users && post.users[uid]) {
        } else {
          post.count++;
          if(!post.users) {
            post.users = {};
          }
          post.users[uid] = true;
        }
      }
      return post;
    })
  }

  /**
   * @return {User|fasle}
   */
  function getUserObjectForDb (user) {
    console.log('get user obj');
    if(!user) return false;
    return {
      displayName: user.displayName || user.uid || false,
      email: user.email || false,
      arbitraryData: 'foo'
    }
  }

  /**
   * Create a user account given a firebase user object.
   * @param {Object} result 
   */ 
  function createUserAccountData(result) {
    console.log('create user account data');
    var uid = result && result.uid || false
    if(!uid) return false;

    var user = getUserObjectForDb(result);

    var path = 'users/' + uid;
    var ref = firebase.database().ref(path);
    return ref.set(user);
  }

</script>


<button onclick="createNewAccount()">Create new account</button>

User creates an account with firebas.auth Then a transaction adds the user details to the user and increments the usersCount

How can something like this be made secure. How can a client be trusted to update a counter at all?

Community
  • 1
  • 1
Snewedon
  • 2,410
  • 2
  • 13
  • 27
  • You'd secure this with security rules. See my answer here for an introduction: http://stackoverflow.com/questions/37954217/is-the-way-the-firebase-database-quickstart-handles-counts-secure/37956590#37956590 – Frank van Puffelen Nov 26 '16 at 05:14
  • Thanks for the link and the quick reply but how can I detect a validation error and retry if there's a concurrency issue. Is there a way to `switch(e)` on the errors returned via a `database().ref().update(updateFun, errorFun);`? I can't find any reference to errors returned by the web SDK in the docs – Snewedon Nov 26 '16 at 07:36
  • Because the user needs to be able to read the value for users count, this means it can be read by anyone, is that a accepted practice? – Snewedon Nov 26 '16 at 08:35
  • The messages exposed from security rules violations are intentionally very general. Transactions are automatically retried though, so you don't need to do that yourself. And yes, if a user needs to update a property based on its existing value, they must be able to read that value. – Frank van Puffelen Nov 26 '16 at 16:18
  • To keep things secure I need to do all the updates at the same time, therefore i've used a multi path update like in you example (see https://bitbucket.org/extinet/firebase-user-counter/src/8875f28a007130164e4f56e77fc2aec63f0ddcc1/?at=v0.2) But now I have the concurrency issue. – Snewedon Nov 27 '16 at 23:15

0 Answers0