1

I'm working on a chat module using fiebase , I have a structure as below .

enter image description here

My main node is mychatexperiment

inside it I have another node ChatListing and some other chat keys.

Today I set up setValues in my structure and when I passed my url without any node it deletes all of my data inside the parent node.

What i want is to set up the rules

  1. One can create the node in any case
  2. One can update the node in any case
  3. One can not delete the node in any case
  4. One Can only update or set the data inside ChatListing

I was trying using this but it does not work . any idea how to implement these things .

{
  "rules": {
         ".write": "!data.exists() || !newData.exists()",
         "read" : true
   }
}

Note : I'm not using any authentication so need to implement rules without any authentication

Revise Requirements :

I have a structure where I have a single parent node and inside it I have multiple chat keys that is generated through firebase , Inside chat keys I have a node of individual message inside that chat . The second thing which is most important is that I have a node called chatlisting in which I am storing my userids in a unique format like If My userid is 5 so inside chatlisting I am storing 5 and inside that 5 I have all the chat keys nodes which are related to me .

{
  "ChatListing": {
    "1126_2": { //userUnique key 

      "MjmhpHb6qR7VSkYzbjI": { // 1126 userid has this chat key and inside this chat last msg was welcome and its unread count is 0 
        "UnReadCount": 0,
        "lastmessage": "Welcome",
        "lastmessagetime": 1631870264251
      }
    },
    "4184_1": {
      "MjmhpHb6qR7VSkYzbjI": { // 4184 userid has this chat key as well and inside this chat last msg was welcome and its unread count is 1 
        "UnReadCount": 1,
        "lastmessage": "Welcome",
        "lastmessagetime": 1.6318646965369204E12
      }
    }

  },
  "MjmhpHb6qR7VSkYzbjI": { // chat key
    "-MjmhpQbBaL7EbHPHayA": { // mesg key
      "data": "Thankyou",
      "time": 1.6318646965369204E12,
      "type": 0,
      "user": 4184   // the msg is sent by this user
    },
    "-Mjn21A4067dT4emYe05": {  // another msg in the same chat
      "data": "Welcome",
      "time": 1631870264251,
      "type": 0,
      "user": 1126 // the msg is sent by this user
    }
  }
}

What I want is to setup the rules in which no one can run update , set or delete inside parent node (except ChatList node) . Any one can create chat keys and read chat keys inside parent node , nothing else they can do .

but inside chatlist they can perform create read , set and update(not delete) as I need to update the last message in this node against user chat .

Faizan Naeem
  • 433
  • 4
  • 13
  • 1
    Does this answer your question? [How to add firebase database rules without authentication?](https://stackoverflow.com/a/68411885/3068190). Just swap out references to `/cars` to `/ChatListing`. – samthecodingman Sep 17 '21 at 13:18
  • @samthecodingman Yes looking very helpful , let me try . Thanks – Faizan Naeem Sep 17 '21 at 13:20
  • tried but does not work , can you guide me @samthecodingman – Faizan Naeem Sep 17 '21 at 13:49
  • What *specifically* doesn't work? Things like "I can still create a node", "I can delete data that I shouldn't be able to", etc. – samthecodingman Sep 17 '21 at 13:52
  • { "rules": { "ChatListing": { ".read": true, ".write": "!data.exists()" } } } – Faizan Naeem Sep 17 '21 at 13:56
  • appying the above in my rules area but can't fetch add update , not able to perform anything – Faizan Naeem Sep 17 '21 at 13:56
  • -- One can create the node in any case -- One can update the node in any case -- One can not delete the node in any case --One Can only update or set the data inside ChatListing – Faizan Naeem Sep 17 '21 at 13:57
  • Please edit in your questions the expanded form of `/ChatListing` and one of the other keys. – samthecodingman Sep 17 '21 at 13:59
  • I should be able to read and create node inside my parent node . I should not be able to delete anything in my structure I should not be able to update and set the nodes inside my parent node except CHatListing – Faizan Naeem Sep 17 '21 at 13:59
  • done . I added the expanded ss – Faizan Naeem Sep 17 '21 at 14:02
  • Security rules are meaningless without the code that exercises them. Please edit your question to show the [minimum, complete/standalone code that we can run against these rules to reproduce the problem](http://stackoverflow.com/help/mcve). – Frank van Puffelen Sep 17 '21 at 14:05
  • Seems expanding the screenshots doesn't reveal what is going on, can you rewrite your database structure in JSON like [shown here](https://stackoverflow.com/a/55196163/3068190) and preferably with comments like [shown here](https://stackoverflow.com/a/67022288/3068190). – samthecodingman Sep 17 '21 at 14:11
  • @samthecodingman done please review – Faizan Naeem Sep 17 '21 at 14:27
  • any luck ? @samthecodingman – Faizan Naeem Sep 17 '21 at 15:13

1 Answers1

2

So reusing the points as covered by my other answer, you would apply those rules using:

{
  "rules": {
    "ChatListing": {
      "$userid": { // the user's unique ID
        // anyone who knows this user ID can read their messages
        ".read": true,

        "$chatid": { // a chatroom the user is in

          // data stored here MUST have this shape (with nothing else)
          // {
          //   UnReadCount: number,
          //   lastmessage: string,
          //   lastmessagetime: number
          // }

          // Data may be created or updated, but not deleted

          ".validate": "newData.child('UnReadCount').isNumber() && newData.child('lastmessage').isString() && newData.child('lastmessagetime').isNumber()",

          "UnReadCount":     { ".write": "newData.exists()" },
          "lastmessage":     { ".write": "newData.exists()" },
          "lastmessagetime": { ".write": "newData.exists()" }
        }
      }
    },
    // when using $ keys at the same level as defined keys,
    // this rule will catch everything that doesn't match
    // the above rules
    "$chatId": { // a chatroom where messages can be sent
      // anyone who knows this chat ID can read its messages
      ".read": true, 

      "$msgId": { // a message in this chatroom

        // Data stored here MUST have this shape (with nothing else)
        // {
        //   data: string,
        //   time: number
        //   type: number,
        //   user: string, // see note
        // }

        // Data may be created, but not edited or deleted
        // change like above if needed

        ".validate": "newData.child('data').isString() && newData.child('time').isNumber() && newData.child('type').isNumber() && newData.child('user').isString()",
        
        "data": { ".write": "!data.exists()" },
        "time": { ".write": "!data.exists()" },
        "type": { ".write": "!data.exists()" },
        "user": { ".write": "!data.exists()" }
      }
    }
  }
}

Notes:

  • Don't use numeric user IDs as they are easily guessable, generate something random. You could even use const userId = push(getReference(getDatabase())).key. Consider securing the data with anonymous authentication.
  • Unlike your requirements, I have made the messages in the chat immutable. Once sent, no one can edit them. This prevents someone other than the sender from coming in and changing the message. With authentication, edits could be allowed because it's more secure.
  • Take note how unlike my /cars example, I haven't put ".read": true at the root of the database or at /ChatListing. This prevents someone coming along and running either of the below pieces of code to pull all of your stored data or pull all stored user IDs at once which will then allow them to find messages not meant for them. It does not prevent brute-forcing the data though.
const rootRef = ref(getDatabase());

rootRef
  .then((snapshot) => {
    console.log(snapshot.val()) // all data in database!
  });

const chatListingRef = ref(getDatabase(), "ChatListing");

chatListingRef
  .then((snapshot) => {
    const usersArray = [];
    const chatIdSet = new Set();
    snapshot.forEach(userData => {
      usersArray.push(userData.key)
      userData.forEach(lastChatData => chatIdSet.add(lastChatData.key));
    });
    
    // logs all user IDs in the database!
    console.log("User IDs:", usersArray)

    // logs all chatroom IDs in the database!
    console.log("Chatroom IDs:", [...chatIdSet]) 
  });
samthecodingman
  • 23,122
  • 4
  • 30
  • 54