@@ -4,15 +4,28 @@ import 'package:dart_leap/dart_leap.dart';
44import 'package:networker/networker.dart' ;
55import 'package:setonix_api/setonix_api.dart' ;
66
7+ const _maxTextLength = 2000 ;
8+ const _maxIdentifierLength = 256 ;
9+ const _maxImagesPerRequest = 100 ;
10+ const _maxPacksPerRequest = 128 ;
11+ const _maxBoardsPerRequest = 256 ;
12+
13+ bool _isReasonableIdentifier (String value) =>
14+ value.isNotEmpty && value.length <= _maxIdentifierLength;
15+
716bool isValidClientEvent (
817 WorldEvent event,
918 Channel channel,
1019 WorldState state, {
1120 required AssetManager assetManager,
1221 ChallengeManager ? challengeManager,
1322}) => switch (event) {
14- TeamJoinRequest () => state.info.teams.containsKey (event.team),
15- TeamLeaveRequest () => state.info.teams.containsKey (event.team),
23+ TeamJoinRequest () =>
24+ _isReasonableIdentifier (event.team) &&
25+ state.info.teams.containsKey (event.team),
26+ TeamLeaveRequest () =>
27+ _isReasonableIdentifier (event.team) &&
28+ state.info.teams.containsKey (event.team),
1629 CellRollRequest () =>
1730 event.object? .inRange (
1831 0 ,
@@ -68,9 +81,19 @@ bool isValidClientEvent(
6881 1 ,
6982 ),
7083 TeamRemoved () => state.info.teams.containsKey (event.team),
71- PacksChangeRequest () => channel == kAuthorityChannel,
84+ PacksChangeRequest () =>
85+ channel == kAuthorityChannel &&
86+ event.packs.length <= _maxPacksPerRequest &&
87+ event.packs.every (_isReasonableIdentifier),
88+ MessageRequest () =>
89+ event.message.isNotEmpty && event.message.length <= _maxTextLength,
90+ BoardsSpawnRequest () =>
91+ _isReasonableIdentifier (event.table) &&
92+ event.assets.length <= _maxBoardsPerRequest &&
93+ event.assets.values.expand ((e) => e).length <= _maxBoardsPerRequest,
7294 BoardMoveRequest () =>
73- event.from != event.to &&
95+ _isReasonableIdentifier (event.table) &&
96+ event.from != event.to &&
7497 event.index.inRange (
7598 0 ,
7699 state
@@ -81,6 +104,11 @@ bool isValidClientEvent(
81104 1 ,
82105 ),
83106 ModeChangeRequest () => channel == kAuthorityChannel,
107+ DialogCloseRequest () => _isReasonableIdentifier (event.id),
108+ ImagesRequest () =>
109+ event.ids.length <= _maxImagesPerRequest &&
110+ event.ids.every (_isReasonableIdentifier),
111+ ToolbarActionRequest () => _isReasonableIdentifier (event.actionId),
84112 _ => true ,
85113};
86114
@@ -228,7 +256,7 @@ Future<ServerResponse?> processClientEvent(
228256 case CellRollRequest ():
229257 final table = state.getTableOrDefault (event.cell.table);
230258 var cell = table.getCell (event.cell.position);
231- final random = Random ();
259+ final random = Random . secure ();
232260 GameObject roll (GameObject object) {
233261 final figure = assetManager.getFigure (object.asset);
234262 if (figure == null || ! figure.rollable) return object;
@@ -255,7 +283,7 @@ Future<ServerResponse?> processClientEvent(
255283 final cell = table.cells[event.cell.position];
256284 if (cell == null ) return null ;
257285 final positions = List <int >.generate (cell.objects.length, (i) => i)
258- ..shuffle ();
286+ ..shuffle (Random . secure () );
259287 return UpdateServerResponse .builder (
260288 CellShuffled (event.cell, positions),
261289 kAnyChannel,
@@ -393,11 +421,13 @@ Future<ServerResponse?> processClientEvent(
393421 if (challengeManager == null ) return null ;
394422 final verified = await event.verify (challenge);
395423 if (! verified) {
424+ final newChallenge = challengeManager.generateNewChallenge (channel);
396425 return UpdateServerResponse .builder (
397- AuthenticatedRequested (challenge , isRequired: true ),
426+ AuthenticatedRequested (newChallenge , isRequired: true ),
398427 channel,
399428 );
400429 }
430+ challengeManager.removeChallenge (channel);
401431 SetonixUser ? user;
402432 try {
403433 user = await userManager? .addUser (
0 commit comments