Submissions: reject XML project files, show submitted file names to admin

This commit is contained in:
2026-09-24 11:32:19 +03:00
parent d81cebef70
commit a8785d48d9
4 changed files with 29 additions and 0 deletions

View File

@@ -38,6 +38,14 @@ class SubmissionService(
val last = submissions.findFirstByStudentIdAndLabIdOrderBySeqDesc(studentId, labId)
val seq = (last?.seq ?: 0) + 1
val payload = files.mapIndexed { i, f -> (f.originalFilename ?: "file$i") to f.bytes }
payload.forEach { (name, bytes) ->
if (looksLikeProjectFile(name, bytes)) {
throw BadRequestException(
"Файл «$name» похож на файл проекта (XML), а не на исходник. " +
"Приложите файл .c/.h или zip с проектом.",
)
}
}
val stored = storage.store(studentId, labId, seq, payload)
val entity = submissions.save(Submission(studentId = studentId, labId = labId, seq = seq))
return toDto(entity, stored.files)
@@ -70,6 +78,22 @@ class SubmissionService(
return perStudent.values.map { toDto(it, filesOf(it)) }
}
/** Файлы с "исходниковым" расширением, содержимое которых — XML-файл проекта (VS/IDE). */
private val sourceExtensions = setOf("c", "h", "cpp", "hpp", "cc", "cxx", "txt")
private fun looksLikeProjectFile(name: String, bytes: ByteArray): Boolean {
val ext = name.substringAfterLast('.', "").lowercase()
if (ext !in sourceExtensions) return false
val head = String(bytes, 0, minOf(bytes.size, 512), Charsets.UTF_8)
.removePrefix("\uFEFF")
.trimStart()
.lowercase()
return head.startsWith("<?xml") ||
head.startsWith("<solution") ||
head.startsWith("<project") ||
head.startsWith("<configurations")
}
private fun filesOf(s: Submission): List<String> =
storage.listFiles(storage.dirFor(s.studentId, s.labId, s.seq))