Open adamduren opened 5 years ago
I think this is going to need some code changes, ideally we let you give us multiple proto files: However we hard code a single file at the moment if you're not using bazel rules. Maybe we should remove that if statement and always name the files uniquely. https://github.com/FirebaseExtended/protobuf-rules-gen/blob/master/firebase_rules_generator/generator.cc#L225
Thoughts? Interested in opening a PR for this? The tests will need to be updated too.
Alternatively, if you want to learn Bazel, someone contributed bazel rules that lets you specify multiple proto files, then concats them together for you, see our example: https://github.com/FirebaseExtended/protobuf-rules-gen/tree/master/example (firestore_rules_binary
can take multiple firestore_rules_proto_library
as deps)
I wrote a little script, which generate me my firestore.rules
from multiple .proto
files. It also keeps the security rules current rules in firestore.rules
.
This is my folder structure:
cloud_firestore
src
protobuf
- person.proto
- user.proto
rules
- firestore.rules
scripts
- generate_protobuf_methods.js
test
- (my unit tests)
This is my firestore.rules
before running the script:
// Start your rules (these don't get generated!)
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
allow write: if isPersonMessage(request.resource.data) &&
request.auth.uid == userId;
}
}
}
This is the result after running my script (node src/scripts/generate_protobuf_methods.js
):
// @@START_GENERATED_FUNCTIONS@@
function isPersonMessage(resource) {
return resource.keys().hasAll(['name']) &&
(resource.keys().hasOnly(['name','phone','email'])) &&
((resource.name is string)) &&
((!resource.keys().hasAny(['email'])) || (resource.email is string)) &&
((!resource.keys().hasAny(['phone'])) || (isPerson_PhoneNumberMessage(resource.phone)));
}
function isPerson_PhoneNumberMessage(resource) {
return resource.keys().hasAll([]) &&
(resource.keys().hasOnly(['type','number'])) &&
((!resource.keys().hasAny(['number'])) || (resource.number is string)) &&
((!resource.keys().hasAny(['type'])) || (isPerson_PhoneTypeEnum(resource.type)));
}
function isPerson_PhoneTypeEnum(resource) {
return resource == 0 ||
resource == 1 ||
resource == 2;
}
function isUserMessage(resource) {
return resource.keys().hasAll([]) &&
(resource.keys().hasOnly(['phone','email'])) &&
((!resource.keys().hasAny(['email'])) || (resource.email is string)) &&
((!resource.keys().hasAny(['phone'])) || (isUser_UserNumberMessage(resource.phone)));
}
function isUser_UserNumberMessage(resource) {
return resource.keys().hasAll([]) &&
(resource.keys().hasOnly(['type','number'])) &&
((!resource.keys().hasAny(['number'])) || (resource.number is string)) &&
((!resource.keys().hasAny(['type'])) || (isUser_UserTypeEnum(resource.type)));
}
function isUser_UserTypeEnum(resource) {
return resource == 0 ||
resource == 1 ||
resource == 2;
}
// @@END_GENERATED_FUNCTIONS@@
// Start your rules (these don't get generated!)
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth.uid == userId;
allow write: if isPersonMessage(request.resource.data) &&
request.auth.uid == userId;
}
}
}
You will find the script under this link: https://gist.github.com/nilsreichardt/9f72898f8bf2aa655d0ef2cce74ac2cf
What is the recommended way of splitting messages across multiple proto files?
I tried sending multiple files to protoc but I get the error
firestore.rules: Tried to write the same file twice.
The next thought was to have abase.proto
which imports the other.proto
files but in trying this I am not sure how to export the imports from thebase.proto
so the output is empty.My last thought is a shell script to execute
protoc
multiple times and then to cat the result together.Any advice / insight would be greatly appreciated!