🪻 distributed transcription service thistle.dunkirk.sh
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add missing input validation on admin endpoints

+53
+43
src/index.ts
··· 48 48 getClassById, 49 49 getClassesForUser, 50 50 getClassMembers, 51 + getMeetingById, 51 52 getMeetingTimesForClass, 52 53 getTranscriptionsForClass, 53 54 isUserEnrolledInClass, ··· 3191 3192 requireAdmin(req); 3192 3193 const classId = req.params.id; 3193 3194 3195 + // Verify class exists 3196 + const existingClass = getClassById(classId); 3197 + if (!existingClass) { 3198 + return Response.json({ error: "Class not found" }, { status: 404 }); 3199 + } 3200 + 3194 3201 deleteClass(classId); 3195 3202 return Response.json({ success: true }); 3196 3203 } catch (error) { ··· 3213 3220 ); 3214 3221 } 3215 3222 3223 + // Verify class exists 3224 + const existingClass = getClassById(classId); 3225 + if (!existingClass) { 3226 + return Response.json({ error: "Class not found" }, { status: 404 }); 3227 + } 3228 + 3216 3229 toggleClassArchive(classId, archived); 3217 3230 return Response.json({ success: true }); 3218 3231 } catch (error) { ··· 3243 3256 return Response.json({ error: "Email required" }, { status: 400 }); 3244 3257 } 3245 3258 3259 + // Verify class exists 3260 + const existingClass = getClassById(classId); 3261 + if (!existingClass) { 3262 + return Response.json({ error: "Class not found" }, { status: 404 }); 3263 + } 3264 + 3246 3265 const user = getUserByEmail(email); 3247 3266 if (!user) { 3248 3267 return Response.json({ error: "User not found" }, { status: 404 }); ··· 3266 3285 return Response.json({ error: "Invalid user ID" }, { status: 400 }); 3267 3286 } 3268 3287 3288 + // Verify class exists 3289 + const existingClass = getClassById(classId); 3290 + if (!existingClass) { 3291 + return Response.json({ error: "Class not found" }, { status: 404 }); 3292 + } 3293 + 3269 3294 removeUserFromClass(userId, classId); 3270 3295 return Response.json({ success: true }); 3271 3296 } catch (error) { ··· 3305 3330 return Response.json({ error: "Label required" }, { status: 400 }); 3306 3331 } 3307 3332 3333 + // Verify class exists 3334 + const existingClass = getClassById(classId); 3335 + if (!existingClass) { 3336 + return Response.json({ error: "Class not found" }, { status: 404 }); 3337 + } 3338 + 3308 3339 const meetingTime = createMeetingTime(classId, label); 3309 3340 return Response.json(meetingTime); 3310 3341 } catch (error) { ··· 3324 3355 return Response.json({ error: "Label required" }, { status: 400 }); 3325 3356 } 3326 3357 3358 + // Verify meeting exists 3359 + const existingMeeting = getMeetingById(meetingId); 3360 + if (!existingMeeting) { 3361 + return Response.json({ error: "Meeting not found" }, { status: 404 }); 3362 + } 3363 + 3327 3364 updateMeetingTime(meetingId, label); 3328 3365 return Response.json({ success: true }); 3329 3366 } catch (error) { ··· 3334 3371 try { 3335 3372 requireAdmin(req); 3336 3373 const meetingId = req.params.id; 3374 + 3375 + // Verify meeting exists 3376 + const existingMeeting = getMeetingById(meetingId); 3377 + if (!existingMeeting) { 3378 + return Response.json({ error: "Meeting not found" }, { status: 404 }); 3379 + } 3337 3380 3338 3381 deleteMeetingTime(meetingId); 3339 3382 return Response.json({ success: true });
+10
src/lib/classes.ts
··· 338 338 } 339 339 340 340 /** 341 + * Get a single meeting time by ID 342 + */ 343 + export function getMeetingById(meetingId: string): MeetingTime | null { 344 + const result = db 345 + .query<MeetingTime, [string]>("SELECT * FROM meeting_times WHERE id = ?") 346 + .get(meetingId); 347 + return result ?? null; 348 + } 349 + 350 + /** 341 351 * Update a meeting time label 342 352 */ 343 353 export function updateMeetingTime(meetingId: string, label: string): void {