SECURITY: enforce profile ownership and immutable identity fields
This commit is contained in:
parent
00c86067cc
commit
50330f6867
|
|
@ -9,10 +9,33 @@ service cloud.firestore {
|
||||||
return signedIn() && request.auth.uid == userId;
|
return signedIn() && request.auth.uid == userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Every user-owned document is isolated by the Firebase UID. Cloudflare R2
|
function validUserCreate(userId) {
|
||||||
// is protected separately by the Worker using the same Firebase ID token.
|
return ownsUser(userId)
|
||||||
|
&& request.resource.data.id == userId
|
||||||
|
&& request.resource.data.keys().hasOnly([
|
||||||
|
'id', 'username', 'displayName', 'profilePhotoUrl', 'bio',
|
||||||
|
'location', 'createdAt', 'updatedAt', 'privacySettings', 'preferences'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function validUserUpdate(userId) {
|
||||||
|
return ownsUser(userId)
|
||||||
|
&& request.resource.data.id == resource.data.id
|
||||||
|
&& request.resource.data.createdAt == resource.data.createdAt
|
||||||
|
&& request.resource.data.keys().hasOnly([
|
||||||
|
'id', 'username', 'displayName', 'profilePhotoUrl', 'bio',
|
||||||
|
'location', 'createdAt', 'updatedAt', 'privacySettings', 'preferences'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Firebase UID is the security boundary. Profile fields are explicitly
|
||||||
|
// allow-listed so clients cannot turn the account document into a secret
|
||||||
|
// or entitlement store.
|
||||||
match /users/{userId} {
|
match /users/{userId} {
|
||||||
allow read, write: if ownsUser(userId);
|
allow create: if validUserCreate(userId);
|
||||||
|
allow read: if ownsUser(userId);
|
||||||
|
allow update: if validUserUpdate(userId);
|
||||||
|
allow delete: if ownsUser(userId);
|
||||||
|
|
||||||
match /rides/{rideId} {
|
match /rides/{rideId} {
|
||||||
allow read, write: if ownsUser(userId);
|
allow read, write: if ownsUser(userId);
|
||||||
|
|
@ -25,7 +48,8 @@ service cloud.firestore {
|
||||||
}
|
}
|
||||||
|
|
||||||
match /motorcycles/{motorcycleId} {
|
match /motorcycles/{motorcycleId} {
|
||||||
allow read, write: if ownsUser(userId);
|
allow read, write: if ownsUser(userId)
|
||||||
|
&& request.resource.data.ownerId == userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
match /trips/{tripId} {
|
match /trips/{tripId} {
|
||||||
|
|
@ -41,8 +65,8 @@ service cloud.firestore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future public/group collections must be added with explicit field-level
|
// Future collaborative resources must get explicit membership/field-level
|
||||||
// authorization. Do not use a global recursive wildcard here.
|
// authorization before they are exposed.
|
||||||
match /groupRides/{groupRideId} {
|
match /groupRides/{groupRideId} {
|
||||||
allow read, write: if false;
|
allow read, write: if false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue