Kast-KIIT commited on
Commit
f1287d6
·
verified ·
1 Parent(s): 2d3be12

File upload no more working in teacher mode "Invalid Submission Error parsing file - Invalid format" - Follow Up Deployment

Browse files
Files changed (1) hide show
  1. index.html +463 -653
index.html CHANGED
@@ -1,689 +1,499 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Secure Coding Assignment Submission</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.15.3/ace.js"></script>
10
- <style>
11
- .editor {
12
- height: 400px;
13
- width: 100%;
14
- font-size: 16px;
15
- }
16
- .typewriter-cursor {
17
- display: inline-block;
18
- width: 10px;
19
- height: 20px;
20
- background-color: #000;
21
- animation: blink 1s step-end infinite;
22
- }
23
- @keyframes blink {
24
- from, to { background-color: transparent }
25
- 50% { background-color: #000; }
26
- }
27
- .hidden {
28
- display: none;
29
- }
30
- .shake {
31
- animation: shake 0.5s;
32
- }
33
- @keyframes shake {
34
- 0%, 100% { transform: translateX(0); }
35
- 20%, 60% { transform: translateX(-5px); }
36
- 40%, 80% { transform: translateX(5px); }
37
- }
38
- </style>
39
  </head>
40
  <body class="bg-gray-100 min-h-screen">
41
- <div class="container mx-auto px-4 py-8">
42
- <!-- App Header -->
43
- <header class="bg-blue-600 text-white p-4 rounded-lg shadow-md mb-8">
44
- <div class="flex justify-between items-center">
45
- <h1 class="text-2xl font-bold">Secure Coding Assignment Submission</h1>
46
- <div id="appMode" class="bg-blue-800 px-3 py-1 rounded-full text-sm">Student Mode</div>
47
- </div>
48
- </header>
49
 
50
- <!-- Mode Selector -->
51
- <div class="bg-white p-4 rounded-lg shadow-md mb-8">
52
- <div class="flex space-x-4">
53
- <button id="studentModeBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Student Mode</button>
54
- <button id="teacherModeBtn" class="bg-gray-600 text-white px-4 py-2 rounded-md hover:bg-gray-700 transition">Teacher Mode</button>
55
- </div>
56
- </div>
57
 
58
- <!-- Student Interface -->
59
- <div id="studentInterface" class="bg-white p-6 rounded-lg shadow-md">
60
- <!-- Student Info Form -->
61
- <div id="studentInfoForm" class="mb-8">
62
- <h2 class="text-xl font-semibold mb-4">Student Information & Assignment Details</h2>
63
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
64
- <div>
65
- <label for="rollNumber" class="block text-sm font-medium text-gray-700 mb-1">Roll Number</label>
66
- <input type="text" id="rollNumber" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
67
- </div>
68
- <div>
69
- <label for="studentName" class="block text-sm font-medium text-gray-700 mb-1">Full Name</label>
70
- <input type="text" id="studentName" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
71
- </div>
72
- <div class="grid grid-cols-2 gap-4">
73
- <div>
74
- <label for="courseName" class="block text-sm font-medium text-gray-700 mb-1">Course Name</label>
75
- <input type="text" id="courseName" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
76
- </div>
77
- <div>
78
- <label for="assignmentNumber" class="block text-sm font-medium text-gray-700 mb-1">Assignment #</label>
79
- <input type="text" id="assignmentNumber" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
80
- </div>
81
- </div>
82
- </div>
83
- <button id="startAssignmentBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Start Assignment</button>
84
  </div>
85
-
86
- <!-- Assignment Area (initially hidden) -->
87
- <div id="assignmentArea" class="hidden">
88
- <div class="flex justify-between items-center mb-4">
89
- <h2 class="text-xl font-semibold">Assignment Editor</h2>
90
- <div class="flex items-center space-x-4">
91
- <div>
92
- <label for="languageSelect" class="block text-sm font-medium text-gray-700 mb-1">Language</label>
93
- <select id="languageSelect" class="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
94
- <option value="plaintext">Plain Text</option>
95
- <option value="python">Python</option>
96
- <option value="java">Java</option>
97
- <option value="c_cpp">C/C++</option>
98
- <option value="javascript">JavaScript</option>
99
- <option value="html">HTML</option>
100
- <option value="css">CSS</option>
101
- </select>
102
- </div>
103
- <div class="text-sm bg-gray-200 px-3 py-1 rounded-full">
104
- <span id="charCount">0</span> characters typed
105
- </div>
106
- </div>
107
  </div>
108
-
109
- <div class="mb-4 p-4 bg-gray-100 rounded-md">
110
- <h3 class="font-medium mb-2">Assignment Instructions:</h3>
111
- <p id="assignmentPrompt" class="text-gray-700">Write a program that prints "Hello, World!" to the console.</p>
112
  </div>
 
 
 
 
113
 
114
- <div class="relative">
115
- <div id="editor" class="editor border border-gray-300 rounded-md"></div>
116
- <div id="typewriterOverlay" class="absolute inset-0 bg-white bg-opacity-90 flex items-center justify-center hidden">
117
- <div class="text-center p-8 max-w-lg">
118
- <h3 class="text-xl font-semibold mb-4">Typewriter Mode Active</h3>
119
- <p class="mb-6">You must type your code character by character. Copy-paste is disabled to ensure academic integrity.</p>
120
- <div class="bg-gray-200 p-4 rounded-md mb-6">
121
- <p class="font-mono text-lg"><span id="typedContent"></span><span class="typewriter-cursor"></span></p>
122
- </div>
123
- <button id="resumeTypingBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Continue Typing</button>
124
- </div>
125
- </div>
 
126
  </div>
127
-
128
- <div class="mt-4 flex justify-between items-center">
129
- <div class="text-sm text-gray-600">
130
- <span id="lastSaved"></span>
131
- </div>
132
- <div class="space-x-2">
133
- <button id="submitAssignmentBtn" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition">Download Assignment</button>
134
- <button id="saveDraftBtn" class="bg-gray-600 text-white px-4 py-2 rounded-md hover:bg-gray-700 transition">Save Draft</button>
135
- </div>
136
  </div>
 
 
 
 
 
 
 
137
 
138
- <div id="studentInfoDisplay" class="mt-6 p-4 bg-gray-100 rounded-md">
139
- <h3 class="font-medium mb-2">Submission Information (Locked)</h3>
140
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
141
- <div>
142
- <p class="text-sm text-gray-600">Roll Number</p>
143
- <p id="displayRollNumber" class="font-medium"></p>
144
- </div>
145
- <div>
146
- <p class="text-sm text-gray-600">Full Name</p>
147
- <p id="displayStudentName" class="font-medium"></p>
148
- </div>
149
- <div class="grid grid-cols-2 gap-4">
150
- <div>
151
- <p class="text-sm text-gray-600">Course Name</p>
152
- <p id="displayCourseName" class="font-medium"></p>
153
- </div>
154
- <div>
155
- <p class="text-sm text-gray-600">Assignment #</p>
156
- <p id="displayAssignmentNumber" class="font-medium"></p>
157
- </div>
158
- </div>
159
  </div>
 
160
  </div>
161
  </div>
162
  </div>
163
 
164
- <!-- Teacher Interface (initially hidden) -->
165
- <div id="teacherInterface" class="bg-white p-6 rounded-lg shadow-md hidden">
166
- <h2 class="text-xl font-semibold mb-4">Teacher Dashboard</h2>
167
-
168
- <div class="mb-6">
169
- <label for="assignmentFile" class="block text-sm font-medium text-gray-700 mb-2">Upload Student Assignment</label>
170
- <div class="flex items-center space-x-4">
171
- <input type="file" id="assignmentFile" accept=".txt,.json" class="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
172
- <button id="uploadAssignmentBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Upload</button>
173
- </div>
174
- <p class="text-sm text-gray-500 mt-2">Only assignments created with this app can be viewed.</p>
175
  </div>
 
176
 
177
- <div id="assignmentVerification" class="hidden p-4 border rounded-md mb-6">
178
- <div class="flex items-center mb-2">
179
- <span id="verificationIcon" class="text-2xl mr-2"></span>
180
- <h3 id="verificationResult" class="font-semibold"></h3>
 
 
 
 
 
181
  </div>
182
- <p id="verificationDetails" class="text-sm"></p>
183
  </div>
 
 
 
184
 
185
- <div id="assignmentViewer" class="hidden">
186
- <div class="flex justify-between items-center mb-4">
187
- <h3 class="text-lg font-medium">Assignment Submission</h3>
188
- <div class="text-sm bg-gray-200 px-3 py-1 rounded-full">
189
- <span id="submissionCharCount">0</span> characters
190
- </div>
191
- </div>
192
 
193
- <div class="mb-4 p-4 bg-gray-100 rounded-md">
194
- <h4 class="font-medium mb-2">Student Information:</h4>
195
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
196
- <div>
197
- <p class="text-sm text-gray-600">Roll Number</p>
198
- <p id="submissionRollNumber" class="font-medium"></p>
199
- </div>
200
- <div>
201
- <p class="text-sm text-gray-600">Full Name</p>
202
- <p id="submissionStudentName" class="font-medium"></p>
203
- </div>
204
-
205
- <div>
206
- <p class="text-sm text-gray-600">Full Name</p>
207
- <p id="submissionCourseName" class="font-medium"></p>
208
- </div>
209
-
210
- <div>
211
- <p class="text-sm text-gray-600">Full Name</p>
212
- <p id="submissionAssignmentNumber" class="font-medium"></p>
213
- </div>
214
- </div>
215
- </div>
216
 
217
- <div class="mb-4 p-4 bg-gray-100 rounded-md">
218
- <h4 class="font-medium mb-2">Assignment Instructions:</h4>
219
- <p id="submissionPrompt" class="text-gray-700"></p>
220
- </div>
 
 
 
 
221
 
222
- <div class="border border-gray-300 rounded-md p-4 bg-white">
223
- <pre id="submissionContent" class="whitespace-pre-wrap font-mono text-sm"></pre>
224
- </div>
 
 
 
225
 
226
- <div class="mt-4 flex justify-end">
227
- <button id="downloadAssignmentBtn" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition">Download Submission</button>
228
- </div>
 
 
 
 
229
  </div>
230
  </div>
231
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  </div>
 
 
233
 
234
- <script>
235
- // DOM Elements
236
- const studentModeBtn = document.getElementById('studentModeBtn');
237
- const teacherModeBtn = document.getElementById('teacherModeBtn');
238
- const appMode = document.getElementById('appMode');
239
- const studentInterface = document.getElementById('studentInterface');
240
- const teacherInterface = document.getElementById('teacherInterface');
241
-
242
- // Student elements
243
- const studentInfoForm = document.getElementById('studentInfoForm');
244
- const assignmentArea = document.getElementById('assignmentArea');
245
- const rollNumberInput = document.getElementById('rollNumber');
246
- const studentNameInput = document.getElementById('studentName');
247
- const courseNameInput = document.getElementById('courseName');
248
- const assignmentNumberInput = document.getElementById('assignmentNumber');
249
- const startAssignmentBtn = document.getElementById('startAssignmentBtn');
250
- const displayRollNumber = document.getElementById('displayRollNumber');
251
- const displayStudentName = document.getElementById('displayStudentName');
252
- const displayCourseName = document.getElementById('displayCourseName');
253
- const displayAssignmentNumber = document.getElementById('displayAssignmentNumber');
254
- const languageSelect = document.getElementById('languageSelect');
255
- const charCount = document.getElementById('charCount');
256
- const submitAssignmentBtn = document.getElementById('submitAssignmentBtn');
257
- const saveDraftBtn = document.getElementById('saveDraftBtn');
258
- const lastSaved = document.getElementById('lastSaved');
259
- const typewriterOverlay = document.getElementById('typewriterOverlay');
260
- const typedContent = document.getElementById('typedContent');
261
- const resumeTypingBtn = document.getElementById('resumeTypingBtn');
262
- // Teacher elements
263
- const assignmentFile = document.getElementById('assignmentFile');
264
- const uploadAssignmentBtn = document.getElementById('uploadAssignmentBtn');
265
- const assignmentVerification = document.getElementById('assignmentVerification');
266
- const verificationIcon = document.getElementById('verificationIcon');
267
- const verificationResult = document.getElementById('verificationResult');
268
- const verificationDetails = document.getElementById('verificationDetails');
269
- const assignmentViewer = document.getElementById('assignmentViewer');
270
- const submissionRollNumber = document.getElementById('submissionRollNumber');
271
- const submissionStudentName = document.getElementById('submissionStudentName');
272
- const submissionCourseName = document.getElementById('submissionCourseName');
273
- const submissionAssignmentNumber = document.getElementById('submissionAssignmentNumber');
274
- const submissionPrompt = document.getElementById('submissionPrompt');
275
- const submissionContent = document.getElementById('submissionContent');
276
- const submissionCharCount = document.getElementById('submissionCharCount');
277
- const downloadAssignmentBtn = document.getElementById('downloadAssignmentBtn');
278
-
279
- // App state
280
- let studentInfoLocked = false;
281
- let editor;
282
- let currentContent = '';
283
- let typedPosition = 0;
284
- let typingTimeout;
285
- let lastSaveTime = null;
286
-
287
- // Initialize ACE Editor
288
- function initEditor() {
289
- editor = ace.edit("editor");
290
- editor.setTheme("ace/theme/chrome");
291
- editor.session.setMode("ace/mode/plain_text");
292
- editor.setOptions({
293
- fontSize: "14px",
294
- enableBasicAutocompletion: false,
295
- enableLiveAutocompletion: false,
296
- showPrintMargin: false,
297
- behavioursEnabled: true
298
- });
299
-
300
- // Enable auto-closing of curly braces
301
- editor.setBehavioursEnabled(true);
302
- editor.commands.addCommand({
303
- name: "insertBraces",
304
- bindKey: {win: '{', mac: '{'},
305
- exec: function(editor) {
306
- editor.insert("{}");
307
- editor.navigateLeft(1);
308
- }
309
- });
310
-
311
- // Disable copy/paste and other unwanted commands
312
- editor.commands.bindKeys({
313
- 'Ctrl-V': null,
314
- 'Command-V': null,
315
- 'Ctrl-C': null,
316
- 'Command-C': null,
317
- 'Ctrl-X': null,
318
- 'Command-X': null
319
- });
320
-
321
- // Track changes to update character count
322
- editor.session.on('change', function() {
323
- if (!studentInfoLocked) return;
324
- updateCharCount();
325
- lastSaveTime = new Date();
326
- updateLastSaved();
327
- });
328
- }
329
-
330
- // Initialize the app
331
- function init() {
332
- initEditor();
333
-
334
- // Keydown handler to prevent copy/paste
335
- editor.container.addEventListener('keydown', function(e) {
336
- if (!studentInfoLocked) return;
337
-
338
- // Block paste events
339
- if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v') {
340
- e.preventDefault();
341
- showTypewriterOverlay();
342
- }
343
- });
344
-
345
- // Mode switching
346
- studentModeBtn.addEventListener('click', () => {
347
- studentInterface.classList.remove('hidden');
348
- teacherInterface.classList.add('hidden');
349
- appMode.textContent = 'Student Mode';
350
- });
351
-
352
- teacherModeBtn.addEventListener('click', () => {
353
- studentInterface.classList.add('hidden');
354
- teacherInterface.classList.remove('hidden');
355
- appMode.textContent = 'Teacher Mode';
356
- });
357
-
358
- // Student form
359
- startAssignmentBtn.addEventListener('click', () => {
360
- const rollNumber = rollNumberInput.value.trim();
361
- const studentName = studentNameInput.value.trim();
362
- const courseName = courseNameInput.value.trim();
363
- const assignmentNumber = assignmentNumberInput.value.trim();
364
-
365
- if (!rollNumber || !studentName || !courseName || !assignmentNumber) {
366
- alert('Please fill in all required fields');
367
- return;
368
- }
369
-
370
- // Lock student info
371
- studentInfoLocked = true;
372
- displayRollNumber.textContent = rollNumber;
373
- displayStudentName.textContent = studentName;
374
- displayCourseName.textContent = courseName;
375
- displayAssignmentNumber.textContent = assignmentNumber;
376
- studentInfoForm.classList.add('hidden');
377
- assignmentArea.classList.remove('hidden');
378
-
379
- // Set focus to editor
380
- editor.focus();
381
- });
382
-
383
- // Language selection
384
- languageSelect.addEventListener('change', () => {
385
- const language = languageSelect.value;
386
- let mode;
387
-
388
- switch(language) {
389
- case 'python': mode = 'ace/mode/python'; break;
390
- case 'java': mode = 'ace/mode/java'; break;
391
- case 'c_cpp': mode = 'ace/mode/c_cpp'; break;
392
- case 'javascript': mode = 'ace/mode/javascript'; break;
393
- case 'html': mode = 'ace/mode/html'; break;
394
- case 'css': mode = 'ace/mode/css'; break;
395
- default: mode = 'ace/mode/plain_text';
396
- }
397
-
398
- editor.session.setMode(mode);
399
- });
400
-
401
- // Save draft
402
- saveDraftBtn.addEventListener('click', () => {
403
- saveDraft();
404
- });
405
-
406
- // Submit assignment
407
- submitAssignmentBtn.addEventListener('click', () => {
408
- submitAssignment();
409
- });
410
-
411
- // Typewriter mode
412
- resumeTypingBtn.addEventListener('click', () => {
413
- typewriterOverlay.classList.add('hidden');
414
- editor.focus();
415
- });
416
-
417
- // Teacher functions
418
- uploadAssignmentBtn.addEventListener('click', () => {
419
- verifyAssignment();
420
- });
421
-
422
- downloadAssignmentBtn.addEventListener('click', () => {
423
- downloadSubmission();
424
- });
425
-
426
- // Auto-save every 30 seconds
427
- setInterval(() => {
428
- if (studentInfoLocked && lastSaveTime) {
429
- saveDraft();
430
- }
431
- }, 30000);
432
-
433
- // Initial update
434
- updateCharCount();
435
- updateLastSaved();
436
- }
437
-
438
- // Show typewriter overlay with strict warning
439
- function showTypewriterOverlay() {
440
- currentContent = editor.getValue();
441
- typedPosition = 0;
442
- typedContent.textContent = '';
443
- typewriterOverlay.classList.remove('hidden');
444
-
445
- // Add warning text
446
- const warning = document.createElement('div');
447
- warning.className = 'text-red-500 font-medium mb-4';
448
- warning.textContent = 'You must type one character at a time!';
449
- typewriterOverlay.querySelector('.text-center').prepend(warning);
450
-
451
- // Start typing animation
452
- typeNextCharacter();
453
- }
454
-
455
- // Type next character animation
456
- function typeNextCharacter() {
457
- if (typedPosition < currentContent.length) {
458
- typedContent.textContent += currentContent.charAt(typedPosition);
459
- typedPosition++;
460
- typingTimeout = setTimeout(typeNextCharacter, Math.random() * 100 + 50);
461
- }
462
- }
463
-
464
- // Update character count
465
- function updateCharCount() {
466
- const content = editor.getValue();
467
- charCount.textContent = content.length;
468
- }
469
-
470
- // Update last saved time
471
- function updateLastSaved() {
472
- if (lastSaveTime) {
473
- const options = {
474
- hour: '2-digit',
475
- minute: '2-digit',
476
- second: '2-digit',
477
- hour12: true
478
- };
479
- lastSaved.textContent = `Last saved: ${lastSaveTime.toLocaleTimeString(undefined, options)}`;
480
- } else {
481
- lastSaved.textContent = 'Not saved yet';
482
- }
483
- }
484
-
485
- // Save draft to localStorage
486
- function saveDraft() {
487
- if (!studentInfoLocked) return;
488
-
489
- const assignmentData = {
490
- rollNumber: displayRollNumber.textContent,
491
- studentName: displayStudentName.textContent,
492
- courseName: displayCourseName.textContent,
493
- assignmentNumber: displayAssignmentNumber.textContent,
494
- language: languageSelect.value,
495
- content: editor.getValue(),
496
- prompt: document.getElementById('assignmentPrompt').textContent,
497
- timestamp: new Date().toISOString(),
498
- signature: generateSignature()
499
- };
500
-
501
- localStorage.setItem('assignmentDraft', JSON.stringify(assignmentData));
502
- lastSaveTime = new Date();
503
- updateLastSaved();
504
-
505
- // Show brief feedback
506
- saveDraftBtn.textContent = 'Saved!';
507
- setTimeout(() => {
508
- saveDraftBtn.textContent = 'Save Draft';
509
- }, 2000);
510
- }
511
-
512
- // Submit assignment
513
- function submitAssignment() {
514
- if (!studentInfoLocked) return;
515
-
516
- const assignmentData = {
517
- rollNumber: displayRollNumber.textContent,
518
- studentName: displayStudentName.textContent,
519
- courseName: displayCourseName.textContent,
520
- assignmentNumber: displayAssignmentNumber.textContent,
521
- language: languageSelect.value,
522
- content: editor.getValue(),
523
- prompt: document.getElementById('assignmentPrompt').textContent,
524
- timestamp: new Date().toISOString(),
525
- signature: generateSignature()
526
- };
527
-
528
- // Create downloadable file with all security features
529
- const blob = new Blob(
530
- [JSON.stringify(assignmentData)], // no pretty-print: fewer chances of stray \r\n
531
- { type: 'application/json;charset=utf-8' } // ✅ explicit
532
- );
533
- const url = URL.createObjectURL(blob);
534
- const a = document.createElement('a');
535
- a.href = url;
536
- a.download = `assignment_${assignmentData.rollNumber}_${new Date().toISOString().slice(0, 10)}.json`;
537
- document.body.appendChild(a);
538
- a.click();
539
- document.body.removeChild(a);
540
- URL.revokeObjectURL(url);
541
-
542
- // Clear draft and reset editor
543
- localStorage.removeItem('assignmentDraft');
544
- editor.setValue('');
545
- updateCharCount();
546
- }
547
-
548
- // Generate a unique signature for the assignment
549
- function generateSignature() {
550
- const data = {
551
- rollNumber: displayRollNumber.textContent,
552
- studentName: displayStudentName.textContent,
553
- content: editor.getValue(),
554
- timestamp: new Date().toISOString()
555
- };
556
-
557
- // In a real app, this would be a more secure hash
558
- return btoa(JSON.stringify(data)).slice(0, 32);
559
- }
560
-
561
- // Verify assignment (teacher mode)
562
- function verifyAssignment() {
563
- const file = assignmentFile.files[0];
564
- if (!file) {
565
- alert('Please select a file to upload');
566
- return;
567
- }
568
-
569
- const reader = new FileReader();
570
- reader.onload = function(e) {
571
- try {
572
- const assignmentData = JSON.parse(e.target.result);
573
-
574
- // Check for required fields
575
- if (!assignmentData.rollNumber || !assignmentData.studentName ||
576
- !assignmentData.content || !assignmentData.signature) {
577
- showVerificationResult(false, "Invalid file format");
578
- return;
579
- }
580
-
581
- // Verify signature
582
- const expectedSignature = generateVerificationSignature(assignmentData);
583
- if (assignmentData.signature !== expectedSignature) {
584
- showVerificationResult(false, "Invalid signature - This file was not created with the Secure Coding App");
585
- return;
586
- }
587
-
588
- // Show assignment
589
- showVerificationResult(true, "Valid assignment submission");
590
- displayAssignment(assignmentData);
591
- } catch (error) {
592
- showVerificationResult(false, "Error parsing file - Invalid format");
593
- }
594
- };
595
- reader.readAsText(file);
596
- }
597
-
598
- // Generate verification signature
599
- function generateVerificationSignature(assignmentData) {
600
- // Must match the same logic as generateSignature()
601
- const data = {
602
- rollNumber: assignmentData.rollNumber,
603
- studentName: assignmentData.studentName,
604
- content: assignmentData.content,
605
- timestamp: assignmentData.timestamp
606
- };
607
-
608
- return btoa(JSON.stringify(data)).slice(0, 32);
609
- }
610
-
611
- // Show verification result
612
- function showVerificationResult(isValid, message) {
613
- assignmentVerification.classList.remove('hidden');
614
-
615
- if (isValid) {
616
- verificationIcon.innerHTML = '<i class="fas fa-check-circle text-green-500"></i>';
617
- verificationResult.textContent = 'Valid Submission';
618
- verificationResult.className = 'font-semibold text-green-600';
619
- } else {
620
- verificationIcon.innerHTML = '<i class="fas fa-times-circle text-red-500"></i>';
621
- verificationResult.textContent = 'Invalid Submission';
622
- verificationResult.className = 'font-semibold text-red-600';
623
- assignmentViewer.classList.add('hidden');
624
- }
625
-
626
- verificationDetails.textContent = message;
627
- }
628
-
629
- // Display assignment (teacher mode)
630
- function displayAssignment(assignmentData) {
631
- submissionRollNumber.textContent = assignmentData.rollNumber;
632
- submissionStudentName.textContent = assignmentData.studentName;
633
- submissionCourseName.textContent = assignmentData.courseName || 'N/A';
634
- submissionAssignmentNumber.textContent = assignmentData.assignmentNumber || 'N/A';
635
- submissionPrompt.textContent = assignmentData.prompt;
636
- submissionContent.textContent = assignmentData.content;
637
- submissionCharCount.textContent = assignmentData.content.length;
638
-
639
- // Set syntax highlighting based on language
640
- let languageClass = '';
641
- switch(assignmentData.language) {
642
- case 'python': languageClass = 'language-python'; break;
643
- case 'java': languageClass = 'language-java'; break;
644
- case 'c_cpp': languageClass = 'language-cpp'; break;
645
- case 'javascript': languageClass = 'language-javascript'; break;
646
- case 'html': languageClass = 'language-html'; break;
647
- case 'css': languageClass = 'language-css'; break;
648
- default: languageClass = '';
649
- }
650
-
651
- submissionContent.className = `whitespace-pre-wrap font-mono text-sm ${languageClass}`;
652
- assignmentViewer.classList.remove('hidden');
653
  }
654
-
655
- // Download submission (teacher mode)
656
- function downloadSubmission() {
657
- if (!assignmentViewer.classList.contains('hidden')) {
658
- const assignmentData = {
659
- rollNumber: submissionRollNumber.textContent,
660
- studentName: submissionStudentName.textContent,
661
- language: languageSelect.value,
662
- content: submissionContent.textContent,
663
- prompt: submissionPrompt.textContent,
664
- timestamp: new Date().toISOString(),
665
- signature: generateVerificationSignature({
666
- rollNumber: submissionRollNumber.textContent,
667
- studentName: submissionStudentName.textContent,
668
- content: submissionContent.textContent,
669
- timestamp: new Date().toISOString()
670
- })
671
- };
672
-
673
- const blob = new Blob([JSON.stringify(assignmentData, null, 2)], { type: 'application/json' });
674
- const url = URL.createObjectURL(blob);
675
- const a = document.createElement('a');
676
- a.href = url;
677
- a.download = `assignment_${assignmentData.rollNumber}_${new Date().toISOString().slice(0, 10)}.json`;
678
- document.body.appendChild(a);
679
- a.click();
680
- document.body.removeChild(a);
681
- URL.revokeObjectURL(url);
682
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
  }
684
-
685
- // Initialize the app when DOM is loaded
686
- document.addEventListener('DOMContentLoaded', init);
687
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
688
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Kast-KIIT/cms" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
689
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Secure Coding Assignment Submission</title>
7
+
8
+ <!-- UI libraries -->
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.15.3/ace.js"></script>
12
+
13
+ <style>
14
+ .editor{height:400px;width:100%;font-size:16px}
15
+ .typewriter-cursor{display:inline-block;width:10px;height:20px;background:#000;animation:blink 1s step-end infinite}
16
+ @keyframes blink{from,to{background:transparent}50%{background:#000}}
17
+ .hidden{display:none}
18
+ .shake{animation:shake .5s}
19
+ @keyframes shake{0%,100%{transform:translateX(0)}20%,60%{transform:translateX(-5px)}40%,80%{transform:translateX(5px)}}
20
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  </head>
22
  <body class="bg-gray-100 min-h-screen">
23
+ <div class="container mx-auto px-4 py-8">
24
+ <!-- ───────────────────────── HEADER ───────────────────────── -->
25
+ <header class="bg-blue-600 text-white p-4 rounded-lg shadow-md mb-8">
26
+ <div class="flex justify-between items-center">
27
+ <h1 class="text-2xl font-bold">Secure Coding Assignment Submission</h1>
28
+ <div id="appMode" class="bg-blue-800 px-3 py-1 rounded-full text-sm">Student Mode</div>
29
+ </div>
30
+ </header>
31
 
32
+ <!-- ───────────────────────── MODE TOGGLE ──────────────────── -->
33
+ <div class="bg-white p-4 rounded-lg shadow-md mb-8">
34
+ <div class="flex space-x-4">
35
+ <button id="studentModeBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Student Mode</button>
36
+ <button id="teacherModeBtn" class="bg-gray-600 text-white px-4 py-2 rounded-md hover:bg-gray-700 transition">Teacher Mode</button>
37
+ </div>
38
+ </div>
39
 
40
+ <!-- ───────────────────────── STUDENT VIEW ─────────────────── -->
41
+ <div id="studentInterface" class="bg-white p-6 rounded-lg shadow-md">
42
+ <!-- Student form -->
43
+ <div id="studentInfoForm" class="mb-8">
44
+ <h2 class="text-xl font-semibold mb-4">Student Information &amp; Assignment Details</h2>
45
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
46
+ <div>
47
+ <label for="rollNumber" class="block text-sm font-medium text-gray-700 mb-1">Roll Number</label>
48
+ <input id="rollNumber" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  </div>
50
+ <div>
51
+ <label for="studentName" class="block text-sm font-medium text-gray-700 mb-1">Full Name</label>
52
+ <input id="studentName" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500">
53
+ </div>
54
+ <div class="grid grid-cols-2 gap-4">
55
+ <div>
56
+ <label for="courseName" class="block text-sm font-medium text-gray-700 mb-1">Course Name</label>
57
+ <input id="courseName" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  </div>
59
+ <div>
60
+ <label for="assignmentNumber" class="block text-sm font-medium text-gray-700 mb-1">Assignment #</label>
61
+ <input id="assignmentNumber" type="text" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500">
 
62
  </div>
63
+ </div>
64
+ </div>
65
+ <button id="startAssignmentBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Start Assignment</button>
66
+ </div>
67
 
68
+ <!-- Assignment editor -->
69
+ <div id="assignmentArea" class="hidden">
70
+ <div class="flex justify-between items-center mb-4">
71
+ <h2 class="text-xl font-semibold">Assignment Editor</h2>
72
+ <div class="flex items-center space-x-4">
73
+ <div>
74
+ <label for="languageSelect" class="block text-sm font-medium text-gray-700 mb-1">Language</label>
75
+ <select id="languageSelect" class="px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500">
76
+ <option value="plaintext">Plain Text</option>
77
+ <option value="python">Python</option><option value="java">Java</option>
78
+ <option value="c_cpp">C/C++</option><option value="javascript">JavaScript</option>
79
+ <option value="html">HTML</option><option value="css">CSS</option>
80
+ </select>
81
  </div>
82
+ <div class="text-sm bg-gray-200 px-3 py-1 rounded-full">
83
+ <span id="charCount">0</span> characters typed
 
 
 
 
 
 
 
84
  </div>
85
+ </div>
86
+ </div>
87
+
88
+ <div class="mb-4 p-4 bg-gray-100 rounded-md">
89
+ <h3 class="font-medium mb-2">Assignment Instructions:</h3>
90
+ <p id="assignmentPrompt" class="text-gray-700">Write a program that prints "Hello, World!" to the console.</p>
91
+ </div>
92
 
93
+ <div class="relative">
94
+ <div id="editor" class="editor border border-gray-300 rounded-md"></div>
95
+ <div id="typewriterOverlay" class="absolute inset-0 bg-white bg-opacity-90 flex items-center justify-center hidden">
96
+ <div class="text-center p-8 max-w-lg">
97
+ <h3 class="text-xl font-semibold mb-4">Typewriter Mode Active</h3>
98
+ <p class="mb-6">You must type your code character by character. Copy-paste is disabled to ensure academic integrity.</p>
99
+ <div class="bg-gray-200 p-4 rounded-md mb-6">
100
+ <p class="font-mono text-lg"><span id="typedContent"></span><span class="typewriter-cursor"></span></p>
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  </div>
102
+ <button id="resumeTypingBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Continue Typing</button>
103
  </div>
104
  </div>
105
  </div>
106
 
107
+ <div class="mt-4 flex justify-between items-center">
108
+ <div class="text-sm text-gray-600"><span id="lastSaved"></span></div>
109
+ <div class="space-x-2">
110
+ <button id="submitAssignmentBtn" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition">Download Assignment</button>
111
+ <button id="saveDraftBtn" class="bg-gray-600 text-white px-4 py-2 rounded-md hover:bg-gray-700 transition">Save Draft</button>
 
 
 
 
 
 
112
  </div>
113
+ </div>
114
 
115
+ <!-- Locked summary -->
116
+ <div id="studentInfoDisplay" class="mt-6 p-4 bg-gray-100 rounded-md">
117
+ <h3 class="font-medium mb-2">Submission Information (Locked)</h3>
118
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
119
+ <div><p class="text-sm text-gray-600">Roll Number</p><p id="displayRollNumber" class="font-medium"></p></div>
120
+ <div><p class="text-sm text-gray-600">Full Name</p><p id="displayStudentName" class="font-medium"></p></div>
121
+ <div class="grid grid-cols-2 gap-4">
122
+ <div><p class="text-sm text-gray-600">Course Name</p><p id="displayCourseName" class="font-medium"></p></div>
123
+ <div><p class="text-sm text-gray-600">Assignment #</p><p id="displayAssignmentNumber" class="font-medium"></p></div>
124
  </div>
 
125
  </div>
126
+ </div>
127
+ </div>
128
+ </div>
129
 
130
+ <!-- ───────────────────────── TEACHER VIEW ──────────────────── -->
131
+ <div id="teacherInterface" class="bg-white p-6 rounded-lg shadow-md hidden">
132
+ <h2 class="text-xl font-semibold mb-4">Teacher Dashboard</h2>
 
 
 
 
133
 
134
+ <!-- Upload -->
135
+ <div class="mb-6">
136
+ <label for="assignmentFile" class="block text-sm font-medium text-gray-700 mb-2">Upload Student Assignment</label>
137
+ <div class="flex items-center space-x-4">
138
+ <input id="assignmentFile" type="file" accept=".json,.sca" class="px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500">
139
+ <button id="uploadAssignmentBtn" class="bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition">Upload</button>
140
+ </div>
141
+ <p class="text-sm text-gray-500 mt-2">Only assignments created with this app can be viewed.</p>
142
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
 
144
+ <!-- Verification banner -->
145
+ <div id="assignmentVerification" class="hidden p-4 border rounded-md mb-6">
146
+ <div class="flex items-center mb-2">
147
+ <span id="verificationIcon" class="text-2xl mr-2"></span>
148
+ <h3 id="verificationResult" class="font-semibold"></h3>
149
+ </div>
150
+ <p id="verificationDetails" class="text-sm"></p>
151
+ </div>
152
 
153
+ <!-- Viewer -->
154
+ <div id="assignmentViewer" class="hidden">
155
+ <div class="flex justify-between items-center mb-4">
156
+ <h3 class="text-lg font-medium">Assignment Submission</h3>
157
+ <div class="text-sm bg-gray-200 px-3 py-1 rounded-full"><span id="submissionCharCount">0</span> characters</div>
158
+ </div>
159
 
160
+ <div class="mb-4 p-4 bg-gray-100 rounded-md">
161
+ <h4 class="font-medium mb-2">Student Information:</h4>
162
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
163
+ <div><p class="text-sm text-gray-600">Roll Number</p><p id="submissionRollNumber" class="font-medium"></p></div>
164
+ <div><p class="text-sm text-gray-600">Full Name</p><p id="submissionStudentName" class="font-medium"></p></div>
165
+ <div><p class="text-sm text-gray-600">Course Name</p><p id="submissionCourseName" class="font-medium"></p></div>
166
+ <div><p class="text-sm text-gray-600">Assignment #</p><p id="submissionAssignmentNumber" class="font-medium"></p></div>
167
  </div>
168
  </div>
169
 
170
+ <div class="mb-4 p-4 bg-gray-100 rounded-md">
171
+ <h4 class="font-medium mb-2">Assignment Instructions:</h4>
172
+ <p id="submissionPrompt" class="text-gray-700"></p>
173
+ </div>
174
+
175
+ <div class="border border-gray-300 rounded-md p-4 bg-white">
176
+ <pre id="submissionContent" class="whitespace-pre-wrap font-mono text-sm"></pre>
177
+ </div>
178
+
179
+ <div class="mt-4 flex justify-end">
180
+ <button id="downloadAssignmentBtn" class="bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700 transition">Download Submission</button>
181
+ </div>
182
  </div>
183
+ </div>
184
+ </div><!-- container -->
185
 
186
+ <!-- ───────────────────────── SCRIPT ────────────────────────── -->
187
+ <script>
188
+ /* ---------- DOM ELEMENTS ---------- */
189
+ const studentModeBtn = document.getElementById('studentModeBtn');
190
+ const teacherModeBtn = document.getElementById('teacherModeBtn');
191
+ const appMode = document.getElementById('appMode');
192
+ const studentInterface= document.getElementById('studentInterface');
193
+ const teacherInterface= document.getElementById('teacherInterface');
194
+
195
+ /* Student */
196
+ const studentInfoForm = document.getElementById('studentInfoForm');
197
+ const assignmentArea = document.getElementById('assignmentArea');
198
+ const rollNumberInput = document.getElementById('rollNumber');
199
+ const studentNameInput= document.getElementById('studentName');
200
+ const courseNameInput = document.getElementById('courseName');
201
+ const assignmentNumberInput = document.getElementById('assignmentNumber');
202
+ const startAssignmentBtn = document.getElementById('startAssignmentBtn');
203
+
204
+ const displayRollNumber = document.getElementById('displayRollNumber');
205
+ const displayStudentName = document.getElementById('displayStudentName');
206
+ const displayCourseName = document.getElementById('displayCourseName');
207
+ const displayAssignmentNumber = document.getElementById('displayAssignmentNumber');
208
+
209
+ const languageSelect = document.getElementById('languageSelect');
210
+ const charCount = document.getElementById('charCount');
211
+ const submitAssignmentBtn = document.getElementById('submitAssignmentBtn');
212
+ const saveDraftBtn = document.getElementById('saveDraftBtn');
213
+ const lastSaved = document.getElementById('lastSaved');
214
+
215
+ const typewriterOverlay= document.getElementById('typewriterOverlay');
216
+ const typedContent = document.getElementById('typedContent');
217
+ const resumeTypingBtn = document.getElementById('resumeTypingBtn');
218
+
219
+ /* Teacher */
220
+ const assignmentFile = document.getElementById('assignmentFile');
221
+ const uploadAssignmentBtn = document.getElementById('uploadAssignmentBtn');
222
+ const assignmentVerification = document.getElementById('assignmentVerification');
223
+ const verificationIcon = document.getElementById('verificationIcon');
224
+ const verificationResult = document.getElementById('verificationResult');
225
+ const verificationDetails = document.getElementById('verificationDetails');
226
+ const assignmentViewer = document.getElementById('assignmentViewer');
227
+
228
+ const submissionRollNumber = document.getElementById('submissionRollNumber');
229
+ const submissionStudentName = document.getElementById('submissionStudentName');
230
+ const submissionCourseName = document.getElementById('submissionCourseName');
231
+ const submissionAssignmentNumber= document.getElementById('submissionAssignmentNumber');
232
+ const submissionPrompt = document.getElementById('submissionPrompt');
233
+ const submissionContent = document.getElementById('submissionContent');
234
+ const submissionCharCount = document.getElementById('submissionCharCount');
235
+ const downloadAssignmentBtn = document.getElementById('downloadAssignmentBtn');
236
+
237
+ /* ---------- APP STATE ---------- */
238
+ let studentInfoLocked = false;
239
+ let editor;
240
+ let lastSaveTime = null;
241
+ let currentContent='', typedPosition=0, typingTimeout;
242
+
243
+ /* ---------- HELPERS ---------- */
244
+ async function sha256(text){
245
+ const data = new TextEncoder().encode(text);
246
+ const digest = await crypto.subtle.digest('SHA-256', data);
247
+ return [...new Uint8Array(digest)].map(b=>b.toString(16).padStart(2,'0')).join('');
248
+ }
249
+
250
+ /* --- Authenticated-Encryption helpers (AES-GCM) --- */
251
+ async function deriveKey(roll, name, ts){
252
+ const seed = new TextEncoder().encode(`${roll}:${name}:${ts}`);
253
+ const hash = await crypto.subtle.digest('SHA-256', seed);
254
+ return crypto.subtle.importKey('raw', hash, 'AES-GCM', false, ['encrypt','decrypt']);
255
+ }
256
+ function strToUtf8(str){ return new TextEncoder().encode(str);}
257
+ function u8ToB64(u8){
258
+ return btoa(String.fromCharCode(...u8));
259
+ }
260
+ function b64ToU8(b64){
261
+ return Uint8Array.from(atob(b64), c=>c.charCodeAt(0));
262
+ }
263
+
264
+ /* Encrypt full assignment object */
265
+ async function encryptAssignment(obj){
266
+ const key = await deriveKey(obj.rollNumber, obj.studentName, obj.timestamp);
267
+ const iv = crypto.getRandomValues(new Uint8Array(12));
268
+ const ad = strToUtf8(`${obj.rollNumber}:${obj.timestamp}`);
269
+
270
+ const plaintext = strToUtf8(JSON.stringify(obj));
271
+ const cipherBuf = await crypto.subtle.encrypt({name:'AES-GCM',iv,additionalData:ad}, key, plaintext);
272
+
273
+ return {
274
+ iv: u8ToB64(iv),
275
+ ad: u8ToB64(ad),
276
+ ct: u8ToB64(new Uint8Array(cipherBuf)),
277
+ meta:{
278
+ rollNumber: obj.rollNumber,
279
+ studentName: obj.studentName,
280
+ timestamp: obj.timestamp,
281
+ alg:'AES-GCM-256'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  }
283
+ };
284
+ }
285
+
286
+ /* Decrypt on Teacher side */
287
+ async function decryptAssignment(pkg){
288
+ const iv = b64ToU8(pkg.iv);
289
+ const ad = b64ToU8(pkg.ad);
290
+ const ct = b64ToU8(pkg.ct);
291
+ const {rollNumber,studentName,timestamp}=pkg.meta;
292
+
293
+ const key = await deriveKey(rollNumber, studentName, timestamp);
294
+ const plainBuf = await crypto.subtle.decrypt({name:'AES-GCM',iv,additionalData:ad}, key, ct);
295
+ return JSON.parse(new TextDecoder().decode(plainBuf));
296
+ }
297
+
298
+ /* ---------- ACE INITIALISATION ---------- */
299
+ function initEditor(){
300
+ editor = ace.edit('editor');
301
+ editor.setTheme('ace/theme/chrome');
302
+ editor.session.setMode('ace/mode/plain_text');
303
+ editor.setOptions({fontSize:'14px',showPrintMargin:false,behavioursEnabled:true});
304
+
305
+ editor.commands.addCommand({
306
+ name:'insertBraces',bindKey:{win:'{',mac:'{'},exec(ed){ed.insert('{}');ed.navigateLeft(1);}
307
+ });
308
+
309
+ editor.commands.bindKeys({'Ctrl-V':null,'Command-V':null,'Ctrl-C':null,'Command-C':null,'Ctrl-X':null,'Command-X':null});
310
+ editor.session.on('change',()=>{
311
+ if(!studentInfoLocked) return;
312
+ updateCharCount(); lastSaveTime=new Date(); updateLastSaved();
313
+ });
314
+ }
315
+
316
+ /* ---------- INITIALISE APP ---------- */
317
+ function init(){
318
+ initEditor();
319
+
320
+ editor.container.addEventListener('keydown',e=>{
321
+ if(!studentInfoLocked) return;
322
+ if((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()==='v'){e.preventDefault();showTypewriterOverlay();}
323
+ });
324
+
325
+ studentModeBtn.onclick = ()=>{studentInterface.classList.remove('hidden');teacherInterface.classList.add('hidden');appMode.textContent='Student Mode';};
326
+ teacherModeBtn.onclick = ()=>{studentInterface.classList.add('hidden');teacherInterface.classList.remove('hidden');appMode.textContent='Teacher Mode';};
327
+
328
+ startAssignmentBtn.onclick = ()=>{
329
+ const roll=rollNumberInput.value.trim(), name=studentNameInput.value.trim(),
330
+ course=courseNameInput.value.trim(), num=assignmentNumberInput.value.trim();
331
+ if(!roll||!name||!course||!num){alert('Please fill in all required fields');return;}
332
+
333
+ studentInfoLocked=true;
334
+ displayRollNumber.textContent=roll;
335
+ displayStudentName.textContent=name;
336
+ displayCourseName.textContent=course;
337
+ displayAssignmentNumber.textContent=num;
338
+ studentInfoForm.classList.add('hidden'); assignmentArea.classList.remove('hidden'); editor.focus();
339
+ };
340
+
341
+ languageSelect.onchange = ()=>{
342
+ const map={python:'python',java:'java',c_cpp:'c_cpp',javascript:'javascript',html:'html',css:'css'};
343
+ editor.session.setMode(`ace/mode/${map[languageSelect.value]||'plain_text'}`);
344
+ };
345
+
346
+ saveDraftBtn.onclick = ()=>{saveDraft();};
347
+ submitAssignmentBtn.onclick = ()=>{submitAssignment();};
348
+ resumeTypingBtn.onclick = ()=>{typewriterOverlay.classList.add('hidden');editor.focus();};
349
+
350
+ uploadAssignmentBtn.onclick = ()=>{verifyAssignment();};
351
+ downloadAssignmentBtn.onclick = ()=>{downloadSubmission();};
352
+
353
+ setInterval(()=>{if(studentInfoLocked&&lastSaveTime){saveDraft();}},30000);
354
+
355
+ updateCharCount(); updateLastSaved();
356
+ }
357
+
358
+ /* ---------- UI HELPERS ---------- */
359
+ function updateCharCount(){charCount.textContent=editor.getValue().length;}
360
+ function updateLastSaved(){
361
+ lastSaved.textContent=lastSaveTime ? `Last saved: ${lastSaveTime.toLocaleTimeString([], {hour:'2-digit',minute:'2-digit',second:'2-digit',hour12:true})}`:'Not saved yet';
362
+ }
363
+
364
+ /* ---------- TYPEWRITER OVERLAY ---------- */
365
+ function showTypewriterOverlay(){
366
+ currentContent=editor.getValue();typedPosition=0;typedContent.textContent='';
367
+ typewriterOverlay.classList.remove('hidden');
368
+ const warn=document.createElement('div');warn.className='text-red-500 font-medium mb-4';warn.textContent='You must type one character at a time!';
369
+ typewriterOverlay.querySelector('.text-center').prepend(warn); typeNextCharacter();
370
+ }
371
+ function typeNextCharacter(){if(typedPosition<currentContent.length){typedContent.textContent+=currentContent.charAt(typedPosition++);typingTimeout=setTimeout(typeNextCharacter,Math.random()*100+50);}}
372
+
373
+ /* ---------- SAVE DRAFT ---------- */
374
+ async function saveDraft(){
375
+ if(!studentInfoLocked) return;
376
+ const data = {
377
+ rollNumber:displayRollNumber.textContent, studentName:displayStudentName.textContent,
378
+ courseName:displayCourseName.textContent, assignmentNumber:displayAssignmentNumber.textContent,
379
+ language:languageSelect.value, content:editor.getValue(),
380
+ prompt:document.getElementById('assignmentPrompt').textContent,
381
+ timestamp:new Date().toISOString(),
382
+ hash:await sha256(editor.getValue())
383
+ };
384
+ localStorage.setItem('assignmentDraft',JSON.stringify(data));
385
+ lastSaveTime=new Date();updateLastSaved();
386
+ saveDraftBtn.textContent='Saved!';setTimeout(()=>{saveDraftBtn.textContent='Save Draft';},2000);
387
+ }
388
+
389
+ /* ---------- SUBMIT / DOWNLOAD (Student) ---------- */
390
+ async function submitAssignment(){
391
+ if(!studentInfoLocked) return;
392
+
393
+ const payload = {
394
+ rollNumber:displayRollNumber.textContent, studentName:displayStudentName.textContent,
395
+ courseName:displayCourseName.textContent, assignmentNumber:displayAssignmentNumber.textContent,
396
+ language:languageSelect.value, content:editor.getValue(),
397
+ prompt:document.getElementById('assignmentPrompt').textContent,
398
+ timestamp:new Date().toISOString(),
399
+ hash:await sha256(editor.getValue())
400
+ };
401
+
402
+ /* ---- Authenticated encryption ---- */
403
+ const encryptedPkg = await encryptAssignment(payload);
404
+ const fileText = JSON.stringify(encryptedPkg); // still JSON but unreadable without key
405
+
406
+ const blob = new Blob([fileText], {type:'application/octet-stream'});
407
+ const url = URL.createObjectURL(blob);
408
+ const a = document.createElement('a');
409
+ a.href=url; a.download=`assignment_${payload.rollNumber}.sca`; document.body.appendChild(a); a.click();
410
+ document.body.removeChild(a); URL.revokeObjectURL(url);
411
+
412
+ localStorage.removeItem('assignmentDraft'); editor.setValue(''); updateCharCount();
413
+ }
414
+
415
+ /* ---------- VERIFY / DECRYPT (Teacher) ---------- */
416
+ async function verifyAssignment(){
417
+ const file=assignmentFile.files[0];if(!file){alert('Please select a file');return;}
418
+ const reader=new FileReader();
419
+ reader.onload=async e=>{
420
+ try{
421
+ const encryptedPkg=JSON.parse(e.target.result);
422
+ const data = await decryptAssignment(encryptedPkg); // throws if tampered
423
+
424
+ /* quick sanity fields */
425
+ const required=['rollNumber','studentName','content','hash'];
426
+ if(required.some(k=>!data[k])){showVerificationResult(false,'Missing required fields');return;}
427
+
428
+ const expectedHash=await sha256(data.content);
429
+ if(expectedHash!==data.hash){showVerificationResult(false,'Content hash mismatch');return;}
430
+
431
+ showVerificationResult(true,'Valid encrypted submission'); displayAssignment(data);
432
+ }catch(err){
433
+ showVerificationResult(false,'Decryption failed – file was modified or wrong key');
434
  }
435
+ };
436
+ reader.readAsText(file);
437
+ }
438
+
439
+ /* ---------- DISPLAY ASSIGNMENT ---------- */
440
+ function displayAssignment(d){
441
+ submissionRollNumber.textContent=d.rollNumber;
442
+ submissionStudentName.textContent=d.studentName;
443
+ submissionCourseName.textContent=d.courseName||'N/A';
444
+ submissionAssignmentNumber.textContent=d.assignmentNumber||'N/A';
445
+ submissionPrompt.textContent=d.prompt;
446
+ submissionContent.textContent=d.content;
447
+ submissionCharCount.textContent=d.content.length;
448
+
449
+ const map={python:'python',java:'java',c_cpp:'cpp',javascript:'javascript',html:'html',css:'css'};
450
+ submissionContent.className=`whitespace-pre-wrap font-mono text-sm language-${map[d.language]||''}`;
451
+ assignmentViewer.classList.remove('hidden');
452
+ }
453
+
454
+ /* ---------- VERIFICATION BANNER ---------- */
455
+ function showVerificationResult(ok,msg){
456
+ assignmentVerification.classList.remove('hidden');
457
+ if(ok){
458
+ verificationIcon.innerHTML='<i class="fas fa-check-circle text-green-500"></i>';
459
+ verificationResult.textContent='Valid Submission';
460
+ verificationResult.className='font-semibold text-green-600';
461
+ }else{
462
+ verificationIcon.innerHTML='<i class="fas fa-times-circle text-red-500"></i>';
463
+ verificationResult.textContent='Invalid Submission';
464
+ verificationResult.className='font-semibold text-red-600';
465
+ assignmentViewer.classList.add('hidden');
466
+ }
467
+ verificationDetails.textContent=msg;
468
+ }
469
+
470
+ /* ---------- DOWNLOAD COPY (Teacher) ---------- */
471
+ async function downloadSubmission(){
472
+ if(assignmentViewer.classList.contains('hidden')) return;
473
+
474
+ /* Collect the data currently displayed */
475
+ const data = {
476
+ rollNumber:submissionRollNumber.textContent,
477
+ studentName:submissionStudentName.textContent,
478
+ courseName:submissionCourseName.textContent,
479
+ assignmentNumber:submissionAssignmentNumber.textContent,
480
+ language:languageSelect.value,
481
+ content:submissionContent.textContent,
482
+ prompt:submissionPrompt.textContent,
483
+ timestamp:new Date().toISOString(),
484
+ hash:await sha256(submissionContent.textContent)
485
+ };
486
+
487
+ const encryptedPkg = await encryptAssignment(data);
488
+ const blob = new Blob([JSON.stringify(encryptedPkg)],{type:'application/octet-stream'});
489
+ const url = URL.createObjectURL(blob);
490
+ const a=document.createElement('a');
491
+ a.href=url; a.download=`assignment_${data.rollNumber}_checked.sca`;
492
+ document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url);
493
+ }
494
+
495
+ /* ---------- INITIALISE ---------- */
496
+ document.addEventListener('DOMContentLoaded',init);
497
+ </script>
498
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Kast-KIIT/cms" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
499
+ </html>