Skip to content

Instantly share code, notes, and snippets.

@asciimike
Created August 20, 2018 18:46
Show Gist options
  • Save asciimike/f18b1991f74f7a266e0d15f31d46d637 to your computer and use it in GitHub Desktop.
Save asciimike/f18b1991f74f7a266e0d15f31d46d637 to your computer and use it in GitHub Desktop.
Firebase Pro Series "Pro Chat" secure chat app (from http://youtu.be/oFlHzF5U-HA)
function isChatMessage(message) {
return message.size() == 4
&& message.username is string
&& message.userId is string
&& message.createdAt is timestamp
&& message.messageText is string
&& message.messageText.size() <= 160;
}
function isUser(user) {
return user.size() == 1
&& (user.role == 'editor' || user.role == 'reader');
}
function isAdminUser(user) {
return user.size() == 1
&& user.role == 'admin';
}
service cloud.firestore {
match /databases/{database}/documents {
match /rooms/{roomId} {
function getRoleForUser(userId) {
return get(/databases/$(database)/documents/rooms/$(roomId)/users/$(userId)).data.role;
}
function roomExists(roomId) {
return exists(/databases/$(database)/documents/rooms/$(roomId));
}
match /messages/{messageId} {
allow create: if isChatMessage(request.resource.data)
&& request.resource.data.userId == request.auth.uid
&& getRoleForUser(request.auth.uid) == 'editor';
allow get, list: if getRoleForUser(request.auth.uid) in ['editor', 'reader'];
}
match /users/{userId} {
allow create: if (!roomExists(roomId)
&& isAdminUser(request.resource.data)
&& request.auth.uid == userId)
|| (getRoleForUser(request.auth.uid) == 'admin'
&& isUser(request.resource.data)
&& request.auth.uid != userId);
}
}
}
}
<html>
<head>
<title>Firebase Pro Series Chat App</title>
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/4.9.0/firebase-firestore.js"></script>
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'></script>
</head>
<body>
<div id="stream">
<h1>Pro Chat</h1>
<input type="text" id="usernameInput" placeholder="Provide a username"/>
<input type="text" id="msgInput" placeholder="Add message"/>
<button type="submit" id="submit">Submit</button>
</br>
</br>
<div id="msg-box"></div>
</div>
<script>
// STEP 0: Configure Firebase
// TODO: Replace with your own config
var config = {
apiKey: ...,
authDomain: ...,
databaseURL: ...,
projectId: ...,
storageBucket: ...,
messagingSenderId: ...
};
firebase.initializeApp(config);
//STEP 1: Create references
var firestore = firebase.firestore();
var auth = firebase.auth();
var uid;
// STEP 2: Log a user in
auth.signInAnonymously().then(user => {
uid = user.uid;
console.log(uid);
// STEP 3: Listen for new messages
firestore.collection('rooms')
.doc('public')
.collection('messages')
.orderBy('createdAt')
.onSnapshot(docs => {
$('#msg-box').empty();
docs.forEach(function (doc) {
var message = doc.data();
$('#msg-box').append($("<div class='msg-text'>").text(message.username).append('<br/>').append($('<span/>').text(message.messageText))).append('<br/>');
});
}, error => {
alert(error);
});
});
//STEP 2: Store messages in Cloud Firestore
$('#submit').on('click', function () {
if (uid !== null) {
var username = $('#usernameInput').val();
var message = $('#msgInput').val();
firestore.collection('rooms')
.doc('public')
.collection('messages')
.add({
'username': username,
'userId': uid,
'createdAt': new Date(),
'messageText': message
}).catch(error => {
alert(error);
});
$('#msgInput').val('');
} else {
alert('You must log in to post!');
}
});
</script>
</body>
</html>
{
"username": "Mike McDonald",
"userId": "7199732f-ec7a-46bd-8949-71cd323a21fd",
"createdAt": "2018-01-29T01:23:45Z",
"messageText": "Hello, World!"
}
{
"role": "editor" // or "reader"
}
@shawnmitchell
Copy link

When should one use this approach and not Custom Claims? https://firebase.google.com/docs/auth/admin/custom-claims

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment