Mark
Mark

Reputation: 9929

Firebase Storage Rules

I'm very new to Firebase so hopefully this is a simple fix ...

I have a couple basic storage rules setup just for testing, however it would seem that the rule for limiting the upload file size is not being honoured:

Storage Rules

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
       allow read: if request.auth != null;
    }
    match /photos/{image} {
       allow write: if request.resource.size < 3 * 1024 * 1024 && request.auth != null;
    }
  }
}

I have followed the rule code from here https://firebase.google.com/docs/storage/security/start

I have been able to upload a file over 5mb. Firebase Storage reports file size of 5.33mb, more than the supposed 3mb limit.

To check that the rule is recognised (that I have the correct path structure) I changed it to only allow a file its name was over 3 characters - I tried to upload a file with a longer name and it didn't permit this as expected.

Edit

Current app side code to upload to Storage (very basic 'messy' setup!). Basically I have a image file picker that returns to onActivityResult:

    private static final String PHOTO_URLS = "photo_links";
    private static final String PHOTOS_DATA = "photos";

    private FirebaseDatabase firebaseDatabase;
    private DatabaseReference photosDatabaseReference;
    private FirebaseStorage firebaseStorage;
    private StorageReference storageReference;
    private OnSuccessListener<UploadTask.TaskSnapshot> uploadSuccessListener;
    private OnFailureListener uploadFailureListener;

    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        firebaseDatabase = FirebaseDatabase.getInstance();
        photosDatabaseReference = firebaseDatabase.getReference().child(PHOTO_URLS);
        firebaseStorage = FirebaseStorage.getInstance();
        storageReference = firebaseStorage.getReference().child(PHOTOS_DATA);
        uploadSuccessListener = taskSnapshot -> photosDatabaseReference.push().setValue(new PhotoEntry(taskSnapshot.getDownloadUrl().toString()));
        uploadFailureListener = Exception::printStackTrace;
    }

    @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(resultCode == RESULT_OK){
            switch(requestCode){
                case REQUEST_CODE_PHOTO:
                    uploadToFirebase(data.getData());
                    break;
                case REQUEST_CODE_AUTH:
                    // stuff to handle Auth ...
                default: break;
            }
        } else if (resultCode == RESULT_CANCELED) {
            makeText(this, "Operation cancelled", LENGTH_SHORT).show();
            if(requestCode == REQUEST_CODE_AUTH) finish();
        }
    }

    private void uploadToFirebase(Uri imageUri) {
        StorageReference reference = storageReference.child(imageUri.getLastPathSegment());
        reference.putFile(imageUri).addOnSuccessListener(uploadSuccessListener).addOnFailureListener(uploadFailureListener);
    }

    @Override protected void onDestroy() {
        super.onDestroy();
        uploadSuccessListener = null;
        uploadFailureListener = null;
    }

Where am I going wrong?

Upvotes: 1

Views: 3049

Answers (1)

Mike McDonald
Mike McDonald

Reputation: 15963

Per the docs, "If multiple rules match a file, the result is the OR of the result of all rules evaluations. That is, if any rule the file matches evalutes to true, the result is true."

Stated another way, your two rules are in conflict: one allows anything anywhere, so long as the request is authenticated; while another requires a file size limit. Unfortunately, due to the above, this means that files can be uploaded regardless of the restriction, since a rule is effectively "overriding" your deeper rule.

You likely want rules that instead look like:

service firebase.storage {
  match /b/{bucket}/o {
    match /anotherPath/{allSubPaths=**} {
       // Only use named paths
       allow write: if request.auth != null;
    }
    match /{allOtherPaths}/{allSubPaths=**} {
       // Or explicitly call out the path you want to avoid in the condition
       allow write: if allOtherPaths!= "photos" && request.auth != null;
    }
    match /photos/{image} {
       allow write: if request.resource.size < 3 * 1024 * 1024 && request.auth != null;
    }
  }
} 

Upvotes: 1

Related Questions