Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best way to split messages into multiple .proto files? #33

Open
adamduren opened this issue May 14, 2019 · 2 comments
Open

Best way to split messages into multiple .proto files? #33

adamduren opened this issue May 14, 2019 · 2 comments

Comments

@adamduren
Copy link

adamduren commented May 14, 2019

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 a base.proto which imports the other .proto files but in trying this I am not sure how to export the imports from the base.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!

@rockwotj
Copy link
Contributor

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)

@nilsreichardt
Copy link

nilsreichardt commented May 27, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants