fix(be): allow querying past contest submissions from public problem#3578
fix(be): allow querying past contest submissions from public problem#3578Choi-Jung-Hyeon wants to merge 9 commits into
Conversation
…page 대회 종료 후 공개 문제로 전환된 problem에서 유저가 대회 당시 제출했던 submission을 조회할 때 EntityNotExistException이 발생하는 버그를 수정한다. Root cause: - getSubmission의 submission 조회 where 조건에 contestId: null이 그대로 전달되어 Prisma가 WHERE contest_id IS NULL을 생성, contestId가 채워진 과거 대회 submission을 찾지 못함 Fix: - contestId/assignmentId가 null인 경우 undefined로 변환하여 해당 필드를 where 조건에서 제외 (no filter) - submission 조회 후 실제 contestId가 존재하면 해당 대회 정보를 로드하여 진행 중인 대회의 타인 제출 열람 차단 로직을 정상 동작하도록 보완 Security: - contestId 없이 공개 엔드포인트를 호출하더라도 submission의 실제 contestId가 진행 중인 대회이면 ForbiddenAccessException으로 차단 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request fixes a bug preventing users from viewing their past contest submissions on public problem pages by ensuring Prisma filters ignore null contest and assignment IDs. It also introduces logic to prevent unauthorized access to submissions from ongoing contests. The reviewer identified a critical security vulnerability where the access control check could be bypassed if a user had not registered for the contest. To resolve this, the reviewer suggests fetching contest and assignment relations directly in the initial database query to ensure consistent security validation and improved performance.
There was a problem hiding this comment.
Pull request overview
Fixes a backend bug where users could not fetch their past contest submissions from a problem page after the contest ended and the problem became public, due to Prisma generating WHERE contest_id IS NULL when contestId=null was passed.
Changes:
- Adjusts
getSubmissionPrismawhereclause to omitcontestId/assignmentIdfilters when they arenull. - Adds a fallback contest load path when the request omits
contestIdbut the fetched submission has acontestId, to preserve “ongoing contest => block viewing others” behavior. - Adds service tests covering public-page access to past contest submissions and a security-related scenario.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| apps/backend/apps/client/src/submission/submission.service.ts | Updates submission lookup filters and adds contest lookup logic for public-page access patterns. |
| apps/backend/apps/client/src/submission/test/submission.service.spec.ts | Adds tests for querying contest submissions via public problem page inputs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…mission - Revert assignmentId filter to keep WHERE assignment_id IS NULL (prevents assignment submissions from leaking to public pages) - Select contest/assignment relations directly in submission query instead of separate contestRecord lookup - Non-participants can no longer bypass ongoing contest access check by omitting contestId parameter - Add non-participant security test case
…hub.com/skkuding/codedang into t2717-closed-contest-problem-submission
학재한테도 물어봤었는데, Contest 관련해서 위 2개 사항이 궁금하네요. |
| assignment: { | ||
| select: { | ||
| startTime: true, | ||
| endTime: true, | ||
| isJudgeResultVisible: true | ||
| } | ||
| }, |
There was a problem hiding this comment.
assignment 검사하는 부분이 삭제되어서 JOIN 연산도 필요없을 것 같습니다.
select도 없애주세요
Description
이 PR은 대회 종료 후 공개 문제로 전환된 페이지에서 유저가 과거 대회 당시 제출했던 내역을 조회할 때 발생하는 버그(
EntityNotExistException)를 수정하고, 해당 과정에서 제기된 보안 및 권한 우회 취약점을 보완합니다.Root Cause & Fix:
getSubmission메서드에서 프론트엔드로부터contestId: null이 넘어올 때, Prisma가WHERE contest_id IS NULL조건을 쿼리하여 과거 대회의contestId가 채워져 있는 제출물을 찾지 못하는 문제가 있었습니다.contestId가 null일 경우 undefined로 변환하여 Prisma 필터에서 제외함으로써 정상 조회가 가능하도록 수정했습니다.Security & Privacy Enforcement:
contestRecord를 2차로 조회하여 대회 접근 권한을 확인했습니다. 하지만 이 방식은 조회자가 '해당 대회의 참가자'가 아닐 경우contestRecord가 null이 되어 진행 중인 대회의 타인 제출물 열람 차단 로직이 우회되는 치명적 취약점이 있었습니다.contestRecord조회를 제거하고, 첫submission쿼리 시에contest와assignment릴레이션 데이터를 조인(Join)하여 바로 가져오도록 로직을 수정했습니다. 이를 통해 대회 비참가자라도 강력하고 일관된 권한 검증을 받게 됩니다.assignmentId에 대한 필터는 원래대로 강제 유지하도록 수정했습니다.Testing:
contestId=null)에서 자신의 과거 대회 제출물 조회 성공 테스트 케이스를 추가했습니다.ForbiddenAccessException으로 정확히 차단되는 테스트 케이스 2종을 추가했습니다.Additional context
submission.service.ts의getSubmission쿼리에서contest,assignment릴레이션을 조인하여 권한을 체크하는 로직(11371150행, 11771185행)이 의도대로 안전하게 구현되었는지, 그리고 과제 제출물 노출 위험이 제대로 차단되었는지 집중적으로 확인해 주시면 좋겠습니다.@libs/exception등의 alias 문제로 실패하던 로컬 테스트 환경을 픽스하여 전체 35개의SubmissionService테스트 케이스가 성공함을 검증했습니다.Before submitting the PR, please make sure you do the following
fixes #123).