Skip to content

Commit 2ae6db4

Browse files
committed
feat(auth): implement user creation and update logic in registry
Adds and refactors data operations for the user model. - Create: A new entry in _itemCreators is added for 'user', enabling user creation through the generic data endpoint. - Update: The updater for 'user' is refactored to be more secure and flexible. It now accepts a raw Map<String, dynamic> from the request body and selectively applies changes for appRole, dashboardRole, and feedDecoratorStatus. This approach prevents mass assignment vulnerabilities while allowing both admins and users to perform their permitted updates.
1 parent 39501df commit 2ae6db4

File tree

1 file changed

+39
-3
lines changed

1 file changed

+39
-3
lines changed

lib/src/registry/data_operation_registry.dart

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ class DataOperationRegistry {
188188
item: item as Language,
189189
userId: uid,
190190
),
191+
// Handler for creating a new user.
192+
'user': (c, item, uid) => c.read<DataRepository<User>>().create(
193+
item: item as User,
194+
userId: uid,
195+
),
191196
'remote_config': (c, item, uid) => c
192197
.read<DataRepository<RemoteConfig>>()
193198
.create(item: item as RemoteConfig, userId: uid),
@@ -220,13 +225,44 @@ class DataOperationRegistry {
220225
'language': (c, id, item, uid) => c
221226
.read<DataRepository<Language>>()
222227
.update(id: id, item: item as Language, userId: uid),
228+
// Custom updater for the 'user' model.
229+
// This updater handles two distinct use cases:
230+
// 1. Admins updating user roles (`appRole`, `dashboardRole`).
231+
// 2. Regular users updating their own `feedDecoratorStatus`.
232+
// It accepts a raw Map<String, dynamic> as the `item` to prevent
233+
// mass assignment vulnerabilities, only applying allowed fields.
223234
'user': (c, id, item, uid) {
224235
final repo = c.read<DataRepository<User>>();
225236
final existingUser = c.read<FetchedItem<dynamic>>().data as User;
226-
final updatedUser = existingUser.copyWith(
227-
feedDecoratorStatus: (item as User).feedDecoratorStatus,
237+
final requestBody = item as Map<String, dynamic>;
238+
239+
AppUserRole? newAppRole;
240+
if (requestBody.containsKey('appRole')) {
241+
newAppRole = AppUserRole.values.byName(
242+
requestBody['appRole'] as String,
243+
);
244+
}
245+
246+
DashboardUserRole? newDashboardRole;
247+
if (requestBody.containsKey('dashboardRole')) {
248+
newDashboardRole = DashboardUserRole.values.byName(
249+
requestBody['dashboardRole'] as String,
250+
);
251+
}
252+
253+
Map<FeedDecoratorType, UserFeedDecoratorStatus>? newStatus;
254+
if (requestBody.containsKey('feedDecoratorStatus')) {
255+
newStatus = User.fromJson(
256+
{'feedDecoratorStatus': requestBody['feedDecoratorStatus']},
257+
).feedDecoratorStatus;
258+
}
259+
260+
final userWithUpdates = existingUser.copyWith(
261+
appRole: newAppRole,
262+
dashboardRole: newDashboardRole,
263+
feedDecoratorStatus: newStatus,
228264
);
229-
return repo.update(id: id, item: updatedUser, userId: uid);
265+
return repo.update(id: id, item: userWithUpdates, userId: uid);
230266
},
231267
'user_app_settings': (c, id, item, uid) => c
232268
.read<DataRepository<UserAppSettings>>()

0 commit comments

Comments
 (0)