Last active
October 19, 2015 02:02
-
-
Save yocontra/b2481bf71d71b39514a1 to your computer and use it in GitHub Desktop.
firebase secure chat room ruleset (using the blaze compiler). users may only post new messages and update their last read date - everything else is handled by the server
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "rules":{ | |
| ".write":"false", | |
| ".read":"false", | |
| "user-rooms": { | |
| ".write":"false", | |
| ".read":"false", | |
| "$userId": { | |
| ".write":"false", | |
| ".read":"(((auth.uid!==null&&auth.uid===$userId)))", | |
| "$roomId": { | |
| ".write":"false", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))", | |
| "ts": { | |
| ".write":"((((newData.parent().val()==null||newData.parent().child('ts').exists()&&newData.parent().child('users').exists()&&newData.parent().child('lastUpdated').exists()&&newData.parent().child('lastRead').exists())&&newData.val()<=now&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isNumber())&&(auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))))", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))" | |
| }, | |
| "lastUpdated": { | |
| ".write":"((((newData.parent().val()==null||newData.parent().child('ts').exists()&&newData.parent().child('users').exists()&&newData.parent().child('lastUpdated').exists()&&newData.parent().child('lastRead').exists())&&newData.val()<=now&&data.exists()&&newData.exists()&&(!newData.exists()||newData.isNumber())&&(auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))))", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))" | |
| }, | |
| "users": { | |
| ".write":"false", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))", | |
| "$userId": { | |
| ".write":"((((newData.parent().parent().val()==null||newData.parent().parent().child('ts').exists()&&newData.parent().parent().child('users').exists()&&newData.parent().parent().child('lastUpdated').exists()&&newData.parent().parent().child('lastRead').exists())&&(!newData.exists()||newData.hasChildren())&&(newData.val()==null||newData.child('first_name').exists()&&newData.child('image').exists())&&newData.child('first_name').exists()&&!data.child('first_name').exists()&&(!newData.child('first_name').exists()||newData.child('first_name').isString())&&newData.child('image').exists()&&!data.child('image').exists()&&(!newData.child('image').exists()||newData.child('image').isString())&&(auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))))", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))", | |
| "first_name": { | |
| ".write":"((((newData.parent().parent().parent().val()==null||newData.parent().parent().parent().child('ts').exists()&&newData.parent().parent().parent().child('users').exists()&&newData.parent().parent().parent().child('lastUpdated').exists()&&newData.parent().parent().parent().child('lastRead').exists())&&(newData.parent().val()==null||newData.parent().child('first_name').exists()&&newData.parent().child('image').exists())&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isString())&&(auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))))", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))" | |
| }, | |
| "image": { | |
| ".write":"((((newData.parent().parent().parent().val()==null||newData.parent().parent().parent().child('ts').exists()&&newData.parent().parent().parent().child('users').exists()&&newData.parent().parent().parent().child('lastUpdated').exists()&&newData.parent().parent().parent().child('lastRead').exists())&&(newData.parent().val()==null||newData.parent().child('first_name').exists()&&newData.parent().child('image').exists())&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isString())&&(auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))))", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))" | |
| }, | |
| "$other":{".validate":"false"} | |
| } | |
| }, | |
| "lastRead": { | |
| ".write":"false", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))", | |
| "$userId": { | |
| ".write":"((((newData.parent().parent().val()==null||newData.parent().parent().child('ts').exists()&&newData.parent().parent().child('users').exists()&&newData.parent().parent().child('lastUpdated').exists()&&newData.parent().parent().child('lastRead').exists())&&auth.uid!==null&&auth.uid===$userId&&newData.val()<=now&&data.exists()&&newData.exists()&&(!newData.exists()||newData.isNumber())&&(auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))))", | |
| ".read":"((auth.uid!==null&&auth.uid===$userId||auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null))" | |
| } | |
| }, | |
| "$other":{".validate":"false"} | |
| } | |
| } | |
| }, | |
| "room-messages": { | |
| ".write":"false", | |
| ".read":"false", | |
| "$roomId": { | |
| ".write":"false", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| "$msgId": { | |
| ".write":"((((!newData.exists()||newData.hasChildren())&&(newData.val()==null||newData.child('user').exists()&&newData.child('text').exists()&&newData.child('ts').exists())&&auth.uid!==null&&auth.uid===newData.child('user').val()&&newData.child('user').exists()&&!data.child('user').exists()&&(!newData.child('user').exists()||newData.child('user').isString())&&newData.child('text').exists()&&!data.child('text').exists()&&(!newData.child('text').exists()||newData.child('text').isString())&&newData.child('ts').val()<=now&&newData.child('ts').exists()&&!data.child('ts').exists()&&(!newData.child('ts').exists()||newData.child('ts').isNumber())&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| "user": { | |
| ".write":"((((newData.parent().val()==null||newData.parent().child('user').exists()&&newData.parent().child('text').exists()&&newData.parent().child('ts').exists())&&auth.uid!==null&&auth.uid===newData.val()&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isString())&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| }, | |
| "text": { | |
| ".write":"((((newData.parent().val()==null||newData.parent().child('user').exists()&&newData.parent().child('text').exists()&&newData.parent().child('ts').exists())&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isString())&&auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| }, | |
| "ts": { | |
| ".write":"((((newData.parent().val()==null||newData.parent().child('user').exists()&&newData.parent().child('text').exists()&&newData.parent().child('ts').exists())&&newData.val()<=now&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isNumber())&&auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| }, | |
| "$other":{".validate":"false"} | |
| } | |
| } | |
| }, | |
| "rooms": { | |
| ".write":"false", | |
| ".read":"false", | |
| "$roomId": { | |
| ".write":"false", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| "ts": { | |
| ".write":"((((newData.parent().val()==null||newData.parent().child('ts').exists()&&newData.parent().child('users').exists()&&newData.parent().child('lastUpdated').exists()&&newData.parent().child('lastRead').exists())&&newData.val()<=now&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isNumber())&&auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| }, | |
| "lastUpdated": { | |
| ".write":"((((newData.parent().val()==null||newData.parent().child('ts').exists()&&newData.parent().child('users').exists()&&newData.parent().child('lastUpdated').exists()&&newData.parent().child('lastRead').exists())&&newData.val()<=now&&data.exists()&&newData.exists()&&(!newData.exists()||newData.isNumber())&&auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| }, | |
| "users": { | |
| ".write":"false", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| "$userId": { | |
| ".write":"((((newData.parent().parent().val()==null||newData.parent().parent().child('ts').exists()&&newData.parent().parent().child('users').exists()&&newData.parent().parent().child('lastUpdated').exists()&&newData.parent().parent().child('lastRead').exists())&&(!newData.exists()||newData.hasChildren())&&(newData.val()==null||newData.child('first_name').exists()&&newData.child('image').exists())&&newData.child('first_name').exists()&&!data.child('first_name').exists()&&(!newData.child('first_name').exists()||newData.child('first_name').isString())&&newData.child('image').exists()&&!data.child('image').exists()&&(!newData.child('image').exists()||newData.child('image').isString())&&auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| "first_name": { | |
| ".write":"((((newData.parent().parent().parent().val()==null||newData.parent().parent().parent().child('ts').exists()&&newData.parent().parent().parent().child('users').exists()&&newData.parent().parent().parent().child('lastUpdated').exists()&&newData.parent().parent().parent().child('lastRead').exists())&&(newData.parent().val()==null||newData.parent().child('first_name').exists()&&newData.parent().child('image').exists())&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isString())&&auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| }, | |
| "image": { | |
| ".write":"((((newData.parent().parent().parent().val()==null||newData.parent().parent().parent().child('ts').exists()&&newData.parent().parent().parent().child('users').exists()&&newData.parent().parent().parent().child('lastUpdated').exists()&&newData.parent().parent().parent().child('lastRead').exists())&&(newData.parent().val()==null||newData.parent().child('first_name').exists()&&newData.parent().child('image').exists())&&newData.exists()&&!data.exists()&&(!newData.exists()||newData.isString())&&auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| }, | |
| "$other":{".validate":"false"} | |
| } | |
| }, | |
| "lastRead": { | |
| ".write":"false", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| "$userId": { | |
| ".write":"((((newData.parent().parent().val()==null||newData.parent().parent().child('ts').exists()&&newData.parent().parent().child('users').exists()&&newData.parent().parent().child('lastUpdated').exists()&&newData.parent().parent().child('lastRead').exists())&&auth.uid!==null&&auth.uid===$userId&&newData.val()<=now&&data.exists()&&newData.exists()&&(!newData.exists()||newData.isNumber())&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))", | |
| ".read":"(((auth.uid!==null&&root.child('rooms').child($roomId).child('users').child(auth.uid).val()!==null)))" | |
| } | |
| }, | |
| "$other":{".validate":"false"} | |
| } | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| functions: | |
| - isLoggedIn(): auth.uid !== null | |
| - isInRoom(roomId): isLoggedIn() && root.rooms[roomId].users[auth.uid] !== null | |
| - isUser(userId): isLoggedIn() && auth.uid === userId | |
| - createOnly(): next.exists() && !prev.exists() | |
| - deleteOnly(): prev.exists() && !next.exists() | |
| - modifyOnly(): prev.exists() && next.exists() | |
| - createOrDelete(): createOnly() || deleteOnly() | |
| schema: | |
| # actual schema | |
| type: object | |
| properties: | |
| user-rooms: | |
| type: object | |
| $userId: | |
| type: object | |
| $roomId: | |
| $ref: "#/definitions/room" | |
| room-messages: | |
| type: object | |
| $roomId: | |
| type: object | |
| $msgId: | |
| $ref: "#/definitions/message" | |
| rooms: | |
| type: object | |
| $roomId: | |
| $ref: "#/definitions/room" | |
| # defs | |
| definitions: | |
| message: | |
| additionalProperties: false | |
| type: object | |
| required: [user, text, ts] | |
| properties: | |
| user: | |
| type: string | |
| constraint: isUser(next) && createOnly() | |
| text: | |
| type: string | |
| constraint: createOnly() | |
| ts: | |
| type: number | |
| constraint: next <= now && createOnly() | |
| user: | |
| additionalProperties: false | |
| type: object | |
| required: [first_name, image] | |
| properties: | |
| first_name: | |
| type: string | |
| constraint: createOnly() | |
| image: | |
| type: string | |
| constraint: createOnly() | |
| room: | |
| additionalProperties: false | |
| type: object | |
| required: [ts, users, lastUpdated, lastRead] | |
| properties: | |
| ts: | |
| type: number | |
| constraint: next <= now && createOnly() | |
| lastUpdated: | |
| type: number | |
| constraint: next <= now && modifyOnly() | |
| users: | |
| type: object | |
| $userId: | |
| $ref: "#/definitions/user" | |
| lastRead: | |
| type: object | |
| $userId: | |
| type: number | |
| constraint: isUser($userId) && next <= now && modifyOnly() | |
| access: | |
| - location: / | |
| read: false | |
| write: false | |
| # room metadata (source of truth) | |
| - location: /rooms/$roomId/ | |
| read: isInRoom($roomId) | |
| write: isInRoom($roomId) | |
| # user room listing (also has metadata) | |
| - location: /user-rooms/$userId/ | |
| read: isUser($userId) | |
| write: isUser($userId) | |
| - location: /user-rooms/$userId/$roomId/ | |
| read: isInRoom($roomId) | |
| write: isInRoom($roomId) | |
| # messages for each room | |
| - location: /room-messages/$roomId/ | |
| read: isInRoom($roomId) | |
| write: isInRoom($roomId) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment