1+ const mongoose = require ( 'mongoose' ) ;
12const ActivityLog = require ( '../models/activityLog' ) ;
23const usersProfiles = require ( '../models/userProfile' ) ;
34
5+ const isValidObjectId = ( id ) =>
6+ mongoose . Types . ObjectId . isValid ( id ) && new mongoose . Types . ObjectId ( id ) . toString ( ) === String ( id ) ;
7+ const sanitizeString = ( str ) => String ( str ) . slice ( 0 , 500 ) ;
8+
49const activityLogController = function ( ) {
510 // Format response - only include assisted_users if is_assisted is true
611 const formatLogs = ( logs ) =>
@@ -30,7 +35,16 @@ const activityLogController = function () {
3035 return res . status ( 403 ) . json ( { error : "Forbidden: Cannot access another student's log" } ) ;
3136 }
3237
33- const logs = await ActivityLog . find ( { actor_id : studentId } )
38+ const authorizedStudentId = requestedStudentId || String ( studentId ) ;
39+ if (
40+ ! authorizedStudentId ||
41+ typeof authorizedStudentId !== 'string' ||
42+ authorizedStudentId . length > 100
43+ ) {
44+ return res . status ( 400 ) . json ( { error : 'Invalid studentId' } ) ;
45+ }
46+
47+ const logs = await ActivityLog . find ( { actor_id : authorizedStudentId } )
3448 . sort ( { created_at : - 1 } )
3549 . select ( 'action_type metadata created_at actor_id is_assisted assisted_users' ) ;
3650
@@ -54,13 +68,15 @@ const activityLogController = function () {
5468 return res . status ( 400 ) . json ( { error : 'actionType and entityId are required' } ) ;
5569 }
5670
57- // Get valid enums
71+ if ( typeof entityId !== 'string' || entityId . length > 200 ) {
72+ return res . status ( 400 ) . json ( { error : 'Invalid entityId' } ) ;
73+ }
74+
5875 const validActionTypes = ActivityLog . schema . path ( 'action_type' ) . enumValues ;
5976 const validAssistanceTypes = ActivityLog . schema
6077 . path ( 'assisted_users' )
6178 . schema . path ( 'assistance_type' ) . enumValues ;
6279
63- // Validate actionType
6480 if ( ! validActionTypes . includes ( actionType ) ) {
6581 return res . status ( 400 ) . json ( {
6682 error : `Invalid actionType. Must be one of: ${ validActionTypes . join ( ', ' ) } ` ,
@@ -72,13 +88,11 @@ const activityLogController = function () {
7288
7389 if ( isAssistedFromClient ) {
7490 if ( ! [ 'Educator' , 'Administrator' ] . includes ( currentUser . role ) ) {
75- // Unauthorized user tried to set the flag
7691 return res . status ( 403 ) . json ( {
7792 error : 'Only educators or administrators can set the assisted flag' ,
7893 } ) ;
7994 }
8095
81- // Authorized user
8296 isAssisted = true ;
8397
8498 if ( ! assistedUsersFromClient || assistedUsersFromClient . length === 0 ) {
@@ -87,10 +101,19 @@ const activityLogController = function () {
87101 } ) ;
88102 }
89103
90- // Fetch and map assisted users
91- const userIds = assistedUsersFromClient . map ( ( u ) => u . userId ) ;
104+ if ( assistedUsersFromClient . length > 50 ) {
105+ return res . status ( 400 ) . json ( { error : 'Too many assisted users' } ) ;
106+ }
107+
108+ const userIds = assistedUsersFromClient . map ( ( u ) => String ( u . userId ) . slice ( 0 , 50 ) ) ;
109+ const uniqueUserIds = [ ...new Set ( userIds ) ] . filter ( isValidObjectId ) ;
110+
111+ if ( uniqueUserIds . length === 0 ) {
112+ return res . status ( 400 ) . json ( { error : 'Invalid assisted user IDs' } ) ;
113+ }
114+
92115 const usersProfile = await usersProfiles
93- . find ( { _id : { $in : userIds } } )
116+ . find ( { _id : { $in : uniqueUserIds } } )
94117 . select ( 'firstName lastName' ) ;
95118
96119 assistedUsers = usersProfile . map ( ( user ) => {
@@ -105,19 +128,30 @@ const activityLogController = function () {
105128
106129 return {
107130 user_id : user . _id ,
108- name : `${ user . firstName } ${ user . lastName } ` ,
131+ name : sanitizeString ( `${ user . firstName } ${ user . lastName } ` ) ,
109132 assisted_at : new Date ( ) ,
110133 assistance_type : assistanceType ,
111134 } ;
112135 } ) ;
113136 }
114137
115- // Build log object
138+ const sanitizedMetadata = { } ;
139+ if ( metadata && typeof metadata === 'object' ) {
140+ for ( const key of Object . keys ( metadata ) . slice ( 0 , 50 ) ) {
141+ const value = metadata [ key ] ;
142+ if ( typeof value === 'string' ) {
143+ sanitizedMetadata [ sanitizeString ( key ) ] = sanitizeString ( value ) ;
144+ } else if ( typeof value === 'number' || typeof value === 'boolean' ) {
145+ sanitizedMetadata [ sanitizeString ( key ) ] = value ;
146+ }
147+ }
148+ }
149+
116150 const logData = {
117151 actor_id : currentUser . requestorId ,
118152 action_type : actionType ,
119- entity_id : entityId ,
120- metadata : metadata || { } ,
153+ entity_id : sanitizeString ( entityId ) ,
154+ metadata : sanitizedMetadata ,
121155 created_at : new Date ( ) ,
122156 is_assisted : isAssisted ,
123157 assisted_users : assistedUsers ,
@@ -145,6 +179,10 @@ const activityLogController = function () {
145179
146180 if ( ! logId ) return res . status ( 400 ) . json ( { error : 'Missing logId' } ) ;
147181
182+ if ( ! isValidObjectId ( logId ) ) {
183+ return res . status ( 400 ) . json ( { error : 'Invalid logId' } ) ;
184+ }
185+
148186 if ( ! [ 'Educator' , 'Administrator' ] . includes ( currentUser . role ) ) {
149187 return res . status ( 403 ) . json ( {
150188 error : 'Only educators or administrators can update the assisted flag' ,
@@ -154,7 +192,6 @@ const activityLogController = function () {
154192 const log = await ActivityLog . findById ( logId ) ;
155193 if ( ! log ) return res . status ( 404 ) . json ( { error : 'Activity log not found' } ) ;
156194
157- // Prepare assisted users only if isAssisted is true
158195 let assistedUsers = [ ] ;
159196 if ( isAssistedFromClient ) {
160197 if ( ! assistedUsersFromClient || assistedUsersFromClient . length === 0 ) {
@@ -163,13 +200,23 @@ const activityLogController = function () {
163200 } ) ;
164201 }
165202
203+ if ( assistedUsersFromClient . length > 50 ) {
204+ return res . status ( 400 ) . json ( { error : 'Too many assisted users' } ) ;
205+ }
206+
166207 const validAssistanceTypes = ActivityLog . schema
167208 . path ( 'assisted_users' )
168209 . schema . path ( 'assistance_type' ) . enumValues ;
169210
170- const userIds = assistedUsersFromClient . map ( ( u ) => u . userId ) ;
211+ const userIds = assistedUsersFromClient . map ( ( u ) => String ( u . userId ) . slice ( 0 , 50 ) ) ;
212+ const uniqueUserIds = [ ...new Set ( userIds ) ] . filter ( isValidObjectId ) ;
213+
214+ if ( uniqueUserIds . length === 0 ) {
215+ return res . status ( 400 ) . json ( { error : 'Invalid assisted user IDs' } ) ;
216+ }
217+
171218 const usersProfile = await usersProfiles
172- . find ( { _id : { $in : userIds } } )
219+ . find ( { _id : { $in : uniqueUserIds } } )
173220 . select ( 'firstName lastName' ) ;
174221
175222 assistedUsers = usersProfile . map ( ( user ) => {
@@ -184,14 +231,13 @@ const activityLogController = function () {
184231
185232 return {
186233 user_id : user . _id ,
187- name : `${ user . firstName } ${ user . lastName } ` ,
234+ name : sanitizeString ( `${ user . firstName } ${ user . lastName } ` ) ,
188235 assisted_at : new Date ( ) ,
189236 assistance_type : assistanceType ,
190237 } ;
191238 } ) ;
192239 }
193240
194- // Update log
195241 log . is_assisted = Boolean ( isAssistedFromClient ) ;
196242 log . assisted_users = assistedUsers ;
197243 await log . save ( ) ;
@@ -212,7 +258,11 @@ const activityLogController = function () {
212258 const { studentId } = req . params ;
213259 const currentUser = req . body . requestor ;
214260 if ( ! studentId ) return res . status ( 400 ) . json ( { error : 'Missing studentId' } ) ;
215- // Add correct rule once you get it so the permission is correct
261+
262+ if ( ! studentId || typeof studentId !== 'string' || studentId . length > 100 ) {
263+ return res . status ( 400 ) . json ( { error : 'Invalid studentId' } ) ;
264+ }
265+
216266 if ( currentUser . role !== 'educator' && currentUser . role !== 'Administrator' ) {
217267 return res . status ( 403 ) . json ( { error : 'Only Educators can view students logs' } ) ;
218268 }
0 commit comments