I am trying to increment "numberOfEvents" field in Users collection whenever an event (in Events collection) is created. How do I do this, I know the below code is wrong I just copied it from firebase documentation. Please help.
rules_version = '2';
const functions = require('firebase-functions');
function increment() {
exports.myFunction = functions.firestore
.document('Events/{docId}')
.onCreate((change, context) => {
get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.numberOfEvents + 1; });
}
service cloud.firestore {
// Do not change this
match /databases/{database}/documents {
// Path to your document
match /Users/{docId} {
allow read;
allow write;
}
match /Events/{docId} {
allow read;
allow write: if get(/databases/$(database)/documents/Users/$(request.auth.uid)).data.numberOfEvents < 16;
}
}
}
Related
Currently, I'm using the default rules for firestore:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
But now I want to permit only logged users to manipulate the data in Firebase, so I found this rule on Internet:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
Now what I have to change in my code to be able to access the db with the logged users? Is there a way to do it globally or I need to change every get in the code? Above is an example of query I have:
await databaseReference
.collection("col1").doc('myDocs').collection(colThings)
.orderBy('day')
.get()
.then((QuerySnapshot snapshot) {
snapshot.docs.forEach((f) => things.add(f.data()));
})
And another question about it: This rule, once running properly, covers all firebase or only Firestore?
My project has 2 main collections: "contact" and "albums".
Here is my data structure
I am trying to assign full read access to everyone in the "albums" collection and to restrict write access to unauthenticated users.
At the same time, i want to assign write access to unauthenticated users and read, update, delete to authenticated users in the "contact" collection.
The current ruleset fails in the rules simulator both for authenticated requests and unauthenticated requests. Rules are as follows:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /contact/{document=**} {
allow create;
allow read, update, delete: if request.auth != null;
}
}
match /albums/{document=**}{
allow read;
allow write: if request.auth != null;
}
}
And the firebase query returns "Uncaught Error in onSnapshot: FirebaseError: Missing or insufficient permissions."
Query below:
useEffect(() => {
const unmount = firestore
.collection("albums")
.orderBy("date", "asc")
.onSnapshot((snapshot) => {
const tempAlbums = [];
snapshot.forEach((doc) => {
tempAlbums.push({ ...doc.data(), id: doc.id });
});
setAlbums(tempAlbums);
});
return unmount;
}, []);
Any ideas on how to correct the rules?
There is a typo in your rules. It should be like this:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /contact/{document=**} {
allow create;
allow read, update, delete: if request.auth != null;
} //The /albums path must be included inside /documents
match /albums/{document=**}{
allow read;
allow write: if request.auth != null;
}
}
}
What I'm trying to achieve is to only show the documents that match request.auth.uid. I've seen these examples on a lot of website but none of them seems to work for me. No matter what article I read I see these examples there but none of them seems to work for me. I have a (posts) collection with bunch of documents with auto-generated (ids).
// I cannot attach more than 2 images it gives me formatting error that's why.
https://i.stack.imgur.com/M84P5.png
https://i.stack.imgur.com/hbBii.png
https://i.stack.imgur.com/lm4HH.png
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if request.auth.uid == resource.data.userId; // This doesn't work
}
}
}
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if request.auth.uid == postId; // This also doesn't work
}
}
}
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if request.auth.uid != null; // even though this works fine but it is general.
}
}
}
Below I've shared my code.
class App extends React.Component {
constructor() {
super();
this.state = { social: [], loggedIn: "false" };
}
componentDidMount = () => {
firestore.collection("posts").onSnapshot((snapshot) => {
const social = snapshot.docs.map((doc) => {
return { id: doc.id, ...doc.data() };
});
this.setState({
social
});
});
};
// clickHandle(id, likes) {
// firestore
// .collection("posts")
// .doc(id)
// .update({ likes: likes + 1 });
// }
handleCreate() {
var obj = { title: "Never Ever GIve Up" };
firestore.collection("posts").add(obj);
}
handleDelete(id) {
firestore.collection("posts").doc(id).delete();
}
handleLogin() {
var provider = new firebase.auth.GoogleAuthProvider();
auth.signInWithPopup(provider).then((result) => {
console.log(result);
});
}
handleLogout() {
firebase.auth().onAuthStateChanged((user) => {
auth.signOut();
});
}
render() {
return (
<div>
<button onClick={this.handleLogin.bind(this)}>Login to Google</button>
<button onClick={this.handleLogout.bind(this)}> Logout from Google</button>
{this.state.social.map((obj) => {
return (
<h1>{obj.title} </h1>
);
})}
<br />
<button id="create" onClick={this.handleCreate.bind(this)}>
Create
</button>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector("#root"));
The problem is that Firestore security rules are not filters. Please read that documentation carefully, and also this blog.
Your query is asking for all documents in the posts collection. However, your rules do not allow that. The rules will not filter the documents that match the rules. Instead, your client app needs to filter for the documents that the user should be able to read, and your rules need to validate that filter.
If you want to require the userId field to be the same as the authenticated user ID for the purpose of reading the document, your query needs to add a filter to ensure they aren't asking for anything more than they have permission to read:
firestore.collection("posts").where("userId", "==", uid)
Where uid is the user ID that you got from the Firebase Auth SDK.
Then your rules can check to see that the filter is correct:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /posts/{postId} {
allow read: if request.auth.uid == resource.data.userId;
}
}
}
I bet you're doing something funky with your requests.
resource.data will return the attributes of the document accessed. In your first example, this will work if the document at path posts/{post_id} has the attribute userId, and the userId attribute matches the uid of the incoming request context. I would verify the structure of each document in the posts collection to check that it matches.
The first example should work, I would double-check the user id matches of the sender. Check the "Authentication" tab of your Firebase console. (In the document shown, looks like the userId is the id of another post, which might indicate some misbehavior?)
The second example won't work because the document doesn't have a postId attribute.
Hello I am working with Firestore and flutter. I need to check the username availability when someone creates a new account.
I want to make that when the user is not connected in the app, the field 'username' of the collection "User Data" can be access with get().
However, the code in rules return several errors of 'expected {' but even if I add the '{', it stills does not accept it.
The code in rule that doesn't work and firebase won't allow me to install this rule:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
match /User Data/{User Data} {
allow read: true;
}
}
What I've tried so far :
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
match /User Data/{User Data} {
allow read: request.resource.data == resource.data.username;
}
}
The code in flutter :
Future<bool> checkUsernameAvailability(String val) async {
final result = await Firestore.instance.collection("User Data").where('username', isEqualTo: val).getDocuments();
return result.documents.isEmpty;
}
onPressed: () async {
final valid = await checkUsernameAvailability(_usernameController.text);
if (!valid) {
error = AppLocalizations.of(context)
.translate('this_username_is_not_available');
} else if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result =
await _auth.registerWithEmailAndPassword(
_emailController.text,
_passwordController.text,
_nameController.text,
_usernameController.text);
if (result == null) {
setState(() {
loading = false;
error = AppLocalizations.of(context)
.translate('please_enter_email');
});
}
}
}
All help is welcomed thanks!
You can seperately write security rules for all collections. When you use match /{document=**} expression to allow read and write for authenticated users, it overrides other rules.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /User Data/{User Data} {
allow read: request.resource.data == resource.data.username
allow write: if request.auth.uid != null;
}
}
addPost = async ({ text, localUri }) => {
const remoteUri = await this.uploadPhotoAsync(localUri);
return new Promise((res, rej) => {
this.firestore
.collection("posts")
.add({
text,
uid: this.uid,
timestamp: this.timestamp,
image: remoteUri
})
.then(ref => {
res(ref);
})
.catch(error => {
rej(error);
});
});
};
And
rules_version = '2';
service firebase.storage {
match /posts/{doc} {
allow read, write: if true;
}
}
Above is my react-native code and below it is the firebase rules for my database so far. Still getting
FirebaseError:[code=permission-denied]: Missing or insufficient permissions.
Any help as to how to fix this code or to make my rules more secure? At this point in the code the user has been authenticated.
The rules in the question are for firebase storage, you need to change the rule for firestore to true:
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Check here for more information:
https://firebase.google.com/docs/firestore/security/insecure-rules