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 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 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