fix: profile photo temp dir, Firestore rules field-level lockdown (batch v0.2.10)
- Move temp profile photos to filesDir/photos/ subdirectory with mkdirs - Update file_paths.xml to scope FileProvider to photos/ subdirectory - Firestore rules: restrict couple doc updates to only mutable fields (streakCount, lastAnsweredAt, wrappedCoupleKey, kdfSalt, kdfParams, encryptionVersion) — prevents client from overwriting currentQuestionId, activePackId, id
This commit is contained in:
parent
9a0b2b6a3d
commit
e7b45cc84f
|
|
@ -105,7 +105,9 @@ fun CreateProfileScreen(
|
||||||
uri?.let { viewModel.setPhotoUri(it.toString()) }
|
uri?.let { viewModel.setPhotoUri(it.toString()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val cameraFile = remember(context) { File(context.filesDir, "profile_temp.jpg") }
|
val cameraFile = remember(context) {
|
||||||
|
File(context.filesDir, "photos/profile_temp.jpg").also { it.parentFile?.mkdirs() }
|
||||||
|
}
|
||||||
val cameraUri = remember(cameraFile) {
|
val cameraUri = remember(cameraFile) {
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
context,
|
context,
|
||||||
|
|
|
||||||
|
|
@ -143,7 +143,9 @@ fun EditProfileContent(
|
||||||
uri?.let { viewModel.setPhotoUri(it.toString()) }
|
uri?.let { viewModel.setPhotoUri(it.toString()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val cameraFile = remember(context) { File(context.filesDir, "profile_edit_temp.jpg") }
|
val cameraFile = remember(context) {
|
||||||
|
File(context.filesDir, "photos/profile_edit_temp.jpg").also { it.parentFile?.mkdirs() }
|
||||||
|
}
|
||||||
val cameraUri = remember(cameraFile) {
|
val cameraUri = remember(cameraFile) {
|
||||||
FileProvider.getUriForFile(
|
FileProvider.getUriForFile(
|
||||||
context,
|
context,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<files-path name="profile_photos" path="." />
|
<files-path name="profile_photos" path="photos/" />
|
||||||
</paths>
|
</paths>
|
||||||
|
|
|
||||||
|
|
@ -179,16 +179,18 @@ service cloud.firestore {
|
||||||
'wrappedCoupleKey', 'kdfSalt', 'kdfParams', 'encryptionVersion']);
|
'wrappedCoupleKey', 'kdfSalt', 'kdfParams', 'encryptionVersion']);
|
||||||
|
|
||||||
// Update: field-level restrictions
|
// Update: field-level restrictions
|
||||||
// - user IDs are immutable (cannot change who is in the couple)
|
// - user IDs, invite code, and createdAt are immutable
|
||||||
// - invite code is immutable (cannot change the code)
|
|
||||||
// - createdAt is immutable (cannot change when the couple was formed)
|
|
||||||
// - encryptionVersion is monotonically non-decreasing (cannot downgrade)
|
// - encryptionVersion is monotonically non-decreasing (cannot downgrade)
|
||||||
// - wrappedCoupleKey/kdfSalt/kdfParams: mutable by members (passphrase change)
|
// - only the explicitly listed mutable fields may change; everything else
|
||||||
// - All other fields (including streakCount and lastAnsweredAt): both members can update
|
// (including currentQuestionId, activePackId, id) is server-only
|
||||||
allow update: if isCouplesMember(coupleId)
|
allow update: if isCouplesMember(coupleId)
|
||||||
&& isImmutable(['userIds', 'inviteCode', 'createdAt'])
|
&& isImmutable(['userIds', 'inviteCode', 'createdAt'])
|
||||||
&& (resource.data.encryptionVersion == null
|
&& (resource.data.encryptionVersion == null
|
||||||
|| request.resource.data.encryptionVersion >= resource.data.encryptionVersion);
|
|| request.resource.data.encryptionVersion >= resource.data.encryptionVersion)
|
||||||
|
&& request.resource.data.diff(resource.data).affectedKeys().hasOnly([
|
||||||
|
'streakCount', 'lastAnsweredAt',
|
||||||
|
'wrappedCoupleKey', 'kdfSalt', 'kdfParams', 'encryptionVersion'
|
||||||
|
]);
|
||||||
|
|
||||||
// Delete: server-only (admin SDK only). Admin SDK bypasses rules.
|
// Delete: server-only (admin SDK only). Admin SDK bypasses rules.
|
||||||
allow delete: if false;
|
allow delete: if false;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue