Skip to content

Commit 98b66d2

Browse files
committed
Improve rules for userGames
Also, don't calculate unfinished games when starting a private game.
1 parent 1e597b1 commit 98b66d2

File tree

3 files changed

+42
-45
lines changed

3 files changed

+42
-45
lines changed

database.rules.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
"users": {
1515
"$userId": {
16-
".write": "auth != null && auth.uid == $userId && data.parent().parent().child('status').val() == 'waiting' && !(root.hasChild('users/' + auth.uid + '/banned') && now < root.child('users/' + auth.uid + '/banned').val())",
16+
".write": "auth != null && auth.uid == $userId && data.parent().parent().child('status').val() == 'waiting' && newData.parent().parent().parent().parent().hasChild('userGames/' + $userId + '/' + $gameId) == newData.exists() && !(root.hasChild('users/' + auth.uid + '/banned') && now < root.child('users/' + auth.uid + '/banned').val())",
1717
".validate": "newData.isNumber() && newData.val() == now"
1818
}
1919
},
@@ -117,7 +117,7 @@
117117
".read": "auth != null",
118118
".indexOn": ".value",
119119
"$gameId": {
120-
".write": "auth != null && auth.uid == $userId",
120+
".write": "auth != null && auth.uid == $userId && newData.parent().parent().parent().hasChild('games/' + $gameId + '/users/' + $userId) == newData.exists()",
121121
".validate": "newData.isNumber() && newData.val() == root.child('games/' + $gameId + '/createdAt').val()"
122122
}
123123
}

functions/src/index.ts

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -258,58 +258,56 @@ export const createGame = functions.https.onCall(async (data, context) => {
258258
"The function must be called while authenticated."
259259
);
260260
}
261-
262261
const userId = context.auth.uid;
263-
const oneHourAgo = Date.now() - 3600000;
264-
const recentGameIds = await admin
265-
.database()
266-
.ref(`userGames/${userId}`)
267-
.orderByValue()
268-
.startAt(oneHourAgo)
269-
.once("value");
270262

271-
const recentGames = await Promise.all(
272-
Object.keys(recentGameIds.val() || {}).map((recentGameId) =>
273-
admin.database().ref(`games/${recentGameId}`).once("value")
274-
)
275-
);
263+
if (access === "public") {
264+
const oneHourAgo = Date.now() - 3600000;
265+
const recentGameIds = await admin
266+
.database()
267+
.ref(`userGames/${userId}`)
268+
.orderByValue()
269+
.startAt(oneHourAgo)
270+
.once("value");
276271

277-
let unfinishedGames = 0;
278-
for (const snap of recentGames) {
279-
if (
280-
snap.child("host").val() === userId &&
281-
snap.child("status").val() !== "done" &&
282-
snap.child("access").val() === "public"
283-
) {
284-
++unfinishedGames;
272+
const recentGames = await Promise.all(
273+
Object.keys(recentGameIds.val() || {}).map((recentGameId) =>
274+
admin.database().ref(`games/${recentGameId}`).once("value")
275+
)
276+
);
277+
278+
let unfinishedGames = 0;
279+
for (const snap of recentGames) {
280+
if (
281+
snap.child("access").val() === "public" &&
282+
snap.child("status").val() !== "done" &&
283+
snap.child("host").val() === userId
284+
) {
285+
++unfinishedGames;
286+
}
287+
}
288+
if (unfinishedGames >= MAX_UNFINISHED_GAMES_PER_HOUR) {
289+
throw new functions.https.HttpsError(
290+
"resource-exhausted",
291+
"Too many unfinished public games were recently created."
292+
);
285293
}
286294
}
287295

288296
const { committed, snapshot } = await admin
289297
.database()
290298
.ref(`games/${gameId}`)
291299
.transaction((currentData) => {
292-
if (currentData === null) {
293-
if (
294-
unfinishedGames >= MAX_UNFINISHED_GAMES_PER_HOUR &&
295-
access === "public"
296-
) {
297-
throw new functions.https.HttpsError(
298-
"resource-exhausted",
299-
"Too many unfinished public games were recently created."
300-
);
301-
}
302-
return {
303-
host: userId,
304-
createdAt: admin.database.ServerValue.TIMESTAMP,
305-
status: "waiting",
306-
access,
307-
mode,
308-
enableHint,
309-
};
310-
} else {
311-
return;
300+
if (currentData !== null) {
301+
return; // the game already exists, bail out
312302
}
303+
return {
304+
host: userId,
305+
createdAt: admin.database.ServerValue.TIMESTAMP,
306+
status: "waiting",
307+
access,
308+
mode,
309+
enableHint,
310+
};
313311
});
314312
if (!committed) {
315313
throw new functions.https.HttpsError(

src/pages/RoomPage.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ function RoomPage({ match, location }) {
6161
useEffect(() => {
6262
if (
6363
!leaving &&
64-
game &&
65-
game.status === "waiting" &&
64+
game?.status === "waiting" &&
6665
(!game.users || !(user.id in game.users))
6766
) {
6867
const updates = {

0 commit comments

Comments
 (0)