Skip to content

Commit 560593d

Browse files
committed
preventing to create firestore users with other fields than userLastConnection
1 parent 03d1d7d commit 560593d

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

cloud/firestore/firestore.default.rules

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ service cloud.firestore {
1111
&& resource.data != null
1212
&& resource.data.diff(request.resource.data).affectedKeys().hasOnly(allowedFieldNames)
1313
}
14+
function onlyAllowedCreatedFields(allowedFieldNames) {
15+
return allowedFieldNames != null
16+
&& request != null
17+
&& request.resource != null
18+
&& request.resource.data != null
19+
&& request.resource.data.diff({}).affectedKeys().hasOnly(allowedFieldNames)
20+
}
1421

1522
// By default, prevent reads & writes on any node
1623
match /{document=**} {
@@ -169,7 +176,8 @@ service cloud.firestore {
169176

170177
match /users/{userId} {
171178
allow list, delete: if false;
172-
allow get, create: if iAm(userId);
179+
allow get: if iAm(userId);
180+
allow create: if iAm(userId) && onlyAllowedCreatedFields(["userLastConnection"]);
173181
allow update: if iAm(userId) && onlyAllowedUpdatedFields(["userLastConnection"]);
174182

175183
match /preferences/self {

cloud/firestore/firestore.default.rules.spec.ts

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,9 @@ const COLLECTIONS: CollectionDescriptor[] = [{
744744
tests: (userContext: UserContext) => {
745745
ensureCollectionFollowAccessPermissions('/users/{userId}', userContext,
746746
{
747-
list: false, createNew: false, delete: false, update: false,
748-
get: userContext.name === 'fred user', createDoc: userContext.name === 'fred user'
747+
list: false, delete: false,
748+
get: userContext.name === 'fred user',
749+
createDoc: 'check-skipped', createNew: 'check-skipped', update: 'check-skipped' // see below for specificities due to userLastConnection field
749750
}, 'fred')
750751

751752
ensureCollectionFollowAccessPermissions('/users/{userId}', userContext,
@@ -755,27 +756,71 @@ const COLLECTIONS: CollectionDescriptor[] = [{
755756
}, 'alice')
756757

757758
if(userContext.name === 'fred user') {
758-
it(`As ${userContext.name}, I should be able to only UPDATE userLastConnection field in my user's infos`, async () => {
759+
it(`As ${userContext.name}, I should be able to only CREATE userLastConnection field in *my user's* infos`, async () => {
760+
await assertSucceeds(setDoc(doc(userContext.context().firestore(),
761+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
762+
), { userLastConnection: new Date().toISOString() }))
763+
})
764+
it(`As ${userContext.name}, I should *NOT* be able to only CREATE userLastConnection field in *another user's* infos`, async () => {
765+
await assertFails(setDoc(doc(userContext.context().firestore(),
766+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'alice')!.path
767+
), { userLastConnection: new Date().toISOString() }))
768+
})
769+
770+
it(`As ${userContext.name}, I should *NOT* be able to CREATE other fields than userLastConnection field in *my user's* infos`, async () => {
771+
await assertSucceeds(setDoc(doc(userContext.context().firestore(),
772+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
773+
), { userLastConnection: new Date().toISOString(), additionalField: "foo", }))
774+
})
775+
it(`As ${userContext.name}, I should *NOT* be able to CREATE other fields than userLastConnection field in *another user's* infos`, async () => {
776+
await assertFails(setDoc(doc(userContext.context().firestore(),
777+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'alice')!.path
778+
), { userLastConnection: new Date().toISOString(), additionalField: "foo", }))
779+
})
780+
781+
it(`As ${userContext.name}, I should be able to only UPDATE userLastConnection field in *my user's* infos`, async () => {
759782
await assertSucceeds(updateDoc(doc(userContext.context().firestore(),
760783
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
761784
), { userLastConnection: new Date().toISOString() }))
762785
})
763-
it(`As ${userContext.name}, I should be able to only UPDATE userLastConnection field in my user's infos`, async () => {
786+
it(`As ${userContext.name}, I should *NOT* be able to only UPDATE userLastConnection field in *another user's* infos`, async () => {
764787
await assertFails(updateDoc(doc(userContext.context().firestore(),
765788
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'alice')!.path
766789
), { userLastConnection: new Date().toISOString() }))
767790
})
768-
} else {
769-
it(`As ${userContext.name}, I should be able to only UPDATE userLastConnection field in my user's infos`, async () => {
791+
792+
it(`As ${userContext.name}, I should *NOT* be able to UPDATE other fields than userLastConnection in *my user's* infos`, async () => {
770793
await assertFails(updateDoc(doc(userContext.context().firestore(),
771794
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
772-
), { userLastConnection: new Date().toISOString() }))
795+
), { userLastConnection: new Date().toISOString(), additionalField: "foo", }))
773796
})
774-
it(`As ${userContext.name}, I should be able to only UPDATE userLastConnection field in my user's infos`, async () => {
797+
it(`As ${userContext.name}, I should *NOT* be able to UPDATE other fields than userLastConnection in *another user's* infos`, async () => {
775798
await assertFails(updateDoc(doc(userContext.context().firestore(),
776799
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'alice')!.path
800+
), { userLastConnection: new Date().toISOString(), additionalField: "foo", }))
801+
})
802+
} else {
803+
it(`As ${userContext.name}, I should *NOT* be able to only CREATE userLastConnection field in *another user's* infos`, async () => {
804+
await assertFails(setDoc(doc(userContext.context().firestore(),
805+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
806+
), { userLastConnection: new Date().toISOString() }))
807+
})
808+
it(`As ${userContext.name}, I should *NOT* be able to CREATE other fields than userLastConnection in *another user's* infos`, async () => {
809+
await assertFails(setDoc(doc(userContext.context().firestore(),
810+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
811+
), { userLastConnection: new Date().toISOString(), additionalField: "foo", }))
812+
})
813+
814+
it(`As ${userContext.name}, I should *NOT* be able to only UPDATE userLastConnection field in *another user's* infos`, async () => {
815+
await assertFails(updateDoc(doc(userContext.context().firestore(),
816+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
777817
), { userLastConnection: new Date().toISOString() }))
778818
})
819+
it(`As ${userContext.name}, I should *NOT* be able to UPDATE other fields than userLastConnection in *another user's* infos`, async () => {
820+
await assertFails(updateDoc(doc(userContext.context().firestore(),
821+
findManagedCollection('/users/{userId}').docInitializations.find(docInit => docInit.name === 'fred')!.path
822+
), { userLastConnection: new Date().toISOString(), additionalField: "foo", }))
823+
})
779824
}
780825
}
781826
}, {

0 commit comments

Comments
 (0)