Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
219 lines (183 sloc) 6.92 KB
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userID} {
allow read: if isAuthenticated();
allow create:
if isUserAuthenticated(userID)
&& validateName()
&& incomingData().likePostCount == 0
&& isRequestedTime(incomingData().createTime)
&& isRequestedTime(incomingData().updateTime);
allow update:
if (isUpdatingMyData() || isUpdatingOnlyLikeCount());
function isUpdatingMyData() {
return isUserAuthenticated(userID)
&& validateName()
&& isNotChanged('likeCount')
&& isRequestedTime(incomingData());
}
function isUpdatingOnlyLikeCount() {
return isUserAuthenticated(userID)
&& (
isIncrementedField('likePostCount', 1)
|| isIncrementedField('likePostCount', -1)
)
&& isNotChanged('name')
}
function validateName() {
return validateString(incomingData().name, 1, 16);
}
match /posts/{postID} {
allow read: if isAuthenticated();
allow create:
if isUserAuthenticated(userID)
&& validateTitle()
&& validateBody()
&& incomingData().author == documentPath(['users', userID])
&& incomingData().likeCount == 0
&& isRequestedTime(incomingData().createTime)
&& isRequestedTime(incomingData().updateTime);
allow update:
if (isUpdatingByAuthor() || isUpdatingByVisitor())
&& isNotChanged('author')
&& isNotChanged('createTime');
function validateTitle() {
return validateString(incomingData().title, 1, 25);
}
function validateBody() {
return validateString(incomingData().body, 1, 1000);
}
function isUpdatingByAuthor() {
return isUserAuthenticated(userID)
&& validateTitle()
&& validateBody()
&& isRequestedTime(incomingData().updateTime)
&& isNotChanged('likeCount');
}
function isUpdatingByVisitor() {
return isAuthenticated()
&& ((
isIncrementedField('likeCount', 1)
&& (!exists(likedUserPath()) && existsAfter(likedUserPath()))
&& (!exists(likedPostPath()) && existsAfter(likedPostPath()))
)
|| (
isIncrementedField('likeCount', -1)
&& (exists(likedUserPath()) && !existsAfter(likedUserPath()))
&& (exists(likedPostPath()) && !existsAfter(likedPostPath()))
)
)
&& isNotChanged('title')
&& isNotChanged('body')
&& isNotChanged('updateTime');
}
function likedUserPath() {
return documentPath(['users', userID, 'posts', postID, 'likedUsers', request.auth.uid]);
}
function likedPostPath() {
return documentPath(['users', request.auth.uid, 'likedPosts', postID]);
}
match /likedUsers/{likedUserID} {
allow read: if isAuthenticated();
allow create:
if isUserAuthenticated(likedUserID)
&& incomingData().id == likedUserID
&& isRequestedTime(incomingData().createTime)
&& !exists(likedPostPath(postID))
&& getAfterData(likedPostPath(postID)).id == postID
&& isIncremented(getAfterData(postPath()), getData(postPath()), 'likeCount', 1)
&& isIncremented(getAfterData(userPath()), getData(userPath()), 'likePostCount', 1);
allow delete:
if isUserAuthenticated(likedUserID)
&& exists(likedPostPath(postID))
&& !existsAfter(likedPostPath(postID))
&& isIncremented(getAfterData(postPath()), getData(postPath()), 'likeCount', -1)
&& isIncremented(getAfterData(userPath()), getData(userPath()), 'likePostCount', -1);
function postPath() {
return documentPath(['users', userID, 'posts', postID]);
}
function userPath() {
return documentPath(['users', likedUserID]);
}
function likedPostPath(postID) {
return documentPath(['users', likedUserID, 'likedPosts', postID]);
}
}
}
match /likedPosts/{likedPostID} {
allow read: if isAuthenticated();
allow create:
if isUserAuthenticated(userID)
&& incomingData().id == likedPostID
&& isRequestedTime(incomingData().createTime)
&& !exists(likedUserPath(userID, incomingData()))
&& getAfterData(likedUserPath(userID, incomingData())).id == userID
&& isIncremented(getAfterData(userPath()), getData(userPath()), 'likePostCount', 1)
&& isIncremented(getAfterData(incomingData().postRef), getData(incomingData().postRef), 'likeCount', 1);
allow delete:
if isUserAuthenticated(userID)
&& exists(likedUserPath(userID, existingData()))
&& !existsAfter(likedUserPath(userID, existingData()))
&& isIncremented(getAfterData(userPath()), getData(userPath()), 'likePostCount', -1)
&& isIncremented(getAfterData(existingData().postRef), getData(existingData().postRef), 'likeCount', -1);
function userPath() {
return documentPath(['users', userID]);
}
function likedUserPath(userID, data) {
return documentPath(['users', get(getData(data.postRef).author).id, 'posts', likedPostID, 'likedUsers', userID]);
}
}
}
match /{path=**}/posts/{postID} {
allow list: if isAuthenticated();
}
match /{path=**}/likedPosts/{likedPostID} {
allow list: if isAuthenticated();
}
match /{path=**}/likedUsers/{likedUserID} {
allow list: if isAuthenticated();
}
function documentPath(paths) {
return path([
['databases', database, 'documents'].join('/'),
paths.join('/')
].join('/'));
}
function isAuthenticated() {
return request.auth != null;
}
function isUserAuthenticated(userID) {
return request.auth.uid == userID;
}
function incomingData() {
return request.resource.data;
}
function existingData() {
return resource.data;
}
function getData(path) {
return get(path).data;
}
function getAfterData(path) {
return getAfter(path).data;
}
function isRequestedTime(time) {
return time == request.time;
}
function validateString(text, min, max) {
return text is string
&& min <= text.size()
&& text.size() <= max;
}
function isNotChanged(key) {
return incomingData()[key] == existingData()[key];
}
function isIncremented(after, before, key, number) {
return after[key] == before[key] + number;
}
function isIncrementedField(key, number) {
return isIncremented(incomingData(), existingData(), key, number);
}
}
}
You can’t perform that action at this time.