FirebaseのCloud Storageにおいて、同一のファイルパスに対して上書きを禁止するのをルールで定義してみる。
どういうことか
例えば、 /foo
ディレクトリ以下に bar.png
を配置するとして、
/foo
以下にbar.png
が 無い時 → アップロードができる/foo
以下にbar.png
が ある時 → アップロードができない
という具合に、上書きを禁止したいケースがある。
その場合は、以下のようにルールを記述して適応する。
service firebase.storage {
match /b/{bucket}/o {
match /foo/{allPaths=**} {
allow read: if ...;
allow create: if request.auth != null && resource == null && request.resource.size < 100 * 1024 * 1024;
}
}
}
認証チェックしたり、ファイルの容量確認の条件も含みで書いているが、
要になるのはresource == null
。指定のパスに既存のファイルがない場合はresource
変数がnullになるので、nullであるならcreate
を許可する。
既に既存のファイルが同じパスに存在している場合はresource
変数がnullでなくなるので、この場合はルールに則って弾くことができる。
最初ハマった間違い
service firebase.storage {
match /b/{bucket}/o {
match /foo/{allPaths=**} {
allow read: if ...;
allow create: if resource.name == null; // ... ①
allow create: if request.resource.name != resource.name; // ... ②
}
}
}
一見、①のものでも良さそうに見えるが、resource
変数がnullだと、resource.name
はundefinedになり、nullとの比較で期待通りにならなくなる。
そしてruleでは、
!resource.name
resource.name === undefined
のようにundefinedであるかどうかをjsのように判別ができないので、気をつけないとハマる。
ならば②であればいけるのでは、、と思うのだが、ruleだとundefinedになる変数にアクセスすると、その条件の評価がerrorとしてみなされるのか、
条件自体が結果的にfalseと解釈されるのでこれも失敗してしまう。
(このあたり、正しく且つ詳しく知っている人が居たら教えて欲しい…)
ので、結果的には最初に示した方法で、既存のパスにファイルが存在しているかをチェックするのが良さそう。
writeではなくcreate?
公式のリファレンスには記載されていないが、writeの権限はcreate
,update
,delete
に分けることができる。
※投稿時点でのものなので、将来的にリファレンスに追記される、あるいは記述できなくなる可能性があります。
updateではだめなのか?
ファイルをアップロードする場合、PUTとして送信されるため、ルールとして走るのはcreate
になってしまう。。
update
で制御できるのは、既に配置されたファイルのmetadata等の情報を更新する場合になる。