manifold/firestore.rules
2022-07-18 18:28:08 -07:00

162 lines
6.3 KiB
Plaintext

rules_version = '2';
// To pick the right project: `firebase projects:list`, then `firebase use <project-name>`
// To deploy: `firebase deploy --only firestore:rules`
service cloud.firestore {
match /databases/{database}/documents {
function isAdmin() {
return request.auth.token.email in [
'akrolsmir@gmail.com',
'ricki.heicklen@gmail.com',
'ross@ftx.org',
'gpimpale29@gmail.com'
]
}
match /stats/stats {
allow read;
}
match /users/{userId} {
allow read;
allow update: if resource.data.id == request.auth.uid
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['bio', 'bannerUrl', 'website', 'twitterHandle', 'discordHandle', 'followedCategories', 'lastPingTime']);
// User referral rules
allow update: if resource.data.id == request.auth.uid
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['referredByUserId', 'referredByContractId', 'referredByGroupId'])
// only one referral allowed per user
&& !("referredByUserId" in resource.data)
// user can't refer themselves
&& !(resource.data.id == request.resource.data.referredByUserId);
// quid pro quos enabled (only once though so nbd) - bc I can't make this work:
// && (get(/databases/$(database)/documents/users/$(request.resource.data.referredByUserId)).referredByUserId == resource.data.id);
}
match /{somePath=**}/portfolioHistory/{portfolioHistoryId} {
allow read;
}
match /users/{userId}/follows/{followUserId} {
allow read;
allow write: if request.auth.uid == userId;
}
match /{somePath=**}/follows/{followUserId} {
allow read;
}
match /private-users/{userId} {
allow read: if resource.data.id == request.auth.uid || isAdmin();
allow update: if (resource.data.id == request.auth.uid || isAdmin())
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['apiKey', 'unsubscribedFromResolutionEmails', 'unsubscribedFromCommentEmails', 'unsubscribedFromAnswerEmails', 'notificationPreferences' ]);
}
match /private-users/{userId}/views/{viewId} {
allow create: if userId == request.auth.uid;
}
match /private-users/{userId}/events/{eventId} {
allow create: if userId == request.auth.uid;
}
match /private-users/{userId}/latency/{loadTimeId} {
allow create: if userId == request.auth.uid;
}
match /private-users/{userId}/cache/{docId} {
allow read: if userId == request.auth.uid || isAdmin();
}
match /contracts/{contractId} {
allow read;
allow update: if request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['tags', 'lowercaseTags', 'groupSlugs']);
allow update: if request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['description', 'closeTime', 'question'])
&& resource.data.creatorId == request.auth.uid;
allow update: if isAdmin();
match /comments/{commentId} {
allow create: if request.auth != null && commentMatchesUser(request.auth.uid, request.resource.data);
}
}
match /{somePath=**}/bets/{betId} {
allow read;
}
match /{somePath=**}/liquidity/{liquidityId} {
allow read;
}
function commentMatchesUser(userId, comment) {
// it's a bad look if someone can impersonate other ids/names/avatars so check everything
let user = get(/databases/$(database)/documents/users/$(userId));
return comment.userId == userId
&& comment.userName == user.data.name
&& comment.userUsername == user.data.username
&& comment.userAvatarUrl == user.data.avatarUrl;
}
match /{somePath=**}/comments/{commentId} {
allow read;
}
match /{somePath=**}/answers/{answerId} {
allow read;
}
match /{somePath=**}/followers/{userId} {
allow read;
allow create, update: if request.auth.uid == userId && request.resource.data.userId == userId;
allow delete: if request.auth.uid == userId;
}
match /txns/{txnId} {
allow read;
}
// Note: `resource` = existing doc, `request.resource` = incoming doc
match /manalinks/{slug} {
// Anyone can view any manalink
allow get;
// Only you can create a manalink with your fromId
allow create: if request.auth.uid == request.resource.data.fromId;
// Only you can list and change your own manalinks
allow list, update: if request.auth.uid == resource.data.fromId;
}
match /users/{userId}/notifications/{notificationId} {
allow read;
allow update: if resource.data.userId == request.auth.uid
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['isSeen', 'viewTime']);
}
match /groups/{groupId} {
allow read;
allow update: if request.auth.uid == resource.data.creatorId
&& request.resource.data.diff(resource.data)
.affectedKeys()
.hasOnly(['name', 'about', 'contractIds', 'memberIds', 'anyoneCanJoin' ]);
allow update: if (request.auth.uid in resource.data.memberIds || resource.data.anyoneCanJoin)
&& request.resource.data.diff(resource.data)
.affectedKeys()
.hasOnly([ 'contractIds', 'memberIds' ]);
allow delete: if request.auth.uid == resource.data.creatorId;
function isMember() {
return request.auth.uid in get(/databases/$(database)/documents/groups/$(groupId)).data.memberIds;
}
match /comments/{commentId} {
allow read;
allow create: if request.auth != null && commentMatchesUser(request.auth.uid, request.resource.data) && isMember();
}
}
}
}