From 9d4f73bb14d40f52eb6fe24540ef7966d2663145 Mon Sep 17 00:00:00 2001 From: ionfwsrijan Date: Sat, 8 Aug 2026 20:40:56 +0530 Subject: [PATCH 01/47] fix: relax role sanitization from exact allow-list to length/sanitization check --- backend/utils/prompts.js | 44 ++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/backend/utils/prompts.js b/backend/utils/prompts.js index 8b0d0e3c..9f14e875 100644 --- a/backend/utils/prompts.js +++ b/backend/utils/prompts.js @@ -1,37 +1,23 @@ -const ALLOWED_ROLES = new Set([ - 'frontend developer', - 'backend developer', - 'full stack developer', - 'react developer', - 'node.js developer', - 'python developer', - 'java developer', - 'devops engineer', - 'cloud engineer', - 'data scientist', - 'machine learning engineer', - 'systems engineer', - 'software engineer', - 'qa engineer', - 'database administrator', - 'web developer', - 'mobile developer', - 'ios developer', - 'android developer', - 'product manager', - 'tech lead', - 'solution architect', - 'security engineer' -]); +const MAX_ROLE_LENGTH = 100; const sanitizeRole = (role) => { if (!role || typeof role !== 'string') { throw new Error('Role must be a non-empty string'); } - const trimmedRole = role.trim().toLowerCase(); - if (!ALLOWED_ROLES.has(trimmedRole)) { - throw new Error(`Invalid role. Allowed roles: ${Array.from(ALLOWED_ROLES).join(', ')}`); + const trimmedRole = role + .trim() + .toLowerCase() + .replace(/[\u0000-\u001f\u007f]/g, '') + .replace(/\s+/g, ' '); + + if (trimmedRole.length === 0) { + throw new Error('Role must be a non-empty string'); } + + if (trimmedRole.length > MAX_ROLE_LENGTH) { + throw new Error(`Role must be at most ${MAX_ROLE_LENGTH} characters`); + } + return trimmedRole; }; @@ -111,4 +97,4 @@ Important: Do NOT add any extra text outside the JSON format. Only return valid `; }; -module.exports = { questionAnswerPrompt, conceptExplainPrompt, interviewTipsPrompt, sanitizeRole, ALLOWED_ROLES }; \ No newline at end of file +module.exports = { questionAnswerPrompt, conceptExplainPrompt, interviewTipsPrompt, sanitizeRole }; \ No newline at end of file From d7f5850a22d9b39783380cafe5e76b0bcf29c3d9 Mon Sep 17 00:00:00 2001 From: sashatakpere Date: Sun, 9 Aug 2026 16:26:26 +0530 Subject: [PATCH 02/47] fix: validate country field input --- frontend/src/pages/Settings/Settings.jsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/Settings/Settings.jsx b/frontend/src/pages/Settings/Settings.jsx index a4fa21c1..4c71a6bf 100644 --- a/frontend/src/pages/Settings/Settings.jsx +++ b/frontend/src/pages/Settings/Settings.jsx @@ -701,15 +701,22 @@ const Settings = () => { + setCountry(e.target.value)} + onChange={(e) => { + const value = e.target.value; + + if (/^[A-Za-z\s'-]*$/.test(value)) { + setCountry(value); + } + }} placeholder="Enter Country" className="w-full bg-slate-50 dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-lg py-2.5 px-4 text-sm text-slate-900 dark:text-white" /> + -

Educational Details From e2d6a03c65dd8c63ac424c9ec3cf8e6005c670f0 Mon Sep 17 00:00:00 2001 From: vedant7007 Date: Mon, 10 Aug 2026 00:04:36 +0530 Subject: [PATCH 03/47] fix: accept object completedTopics in saveProgress so progress persists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The controller required completedTopics to be an Array, but the frontend, the Zod validator (z.record), the Mongoose schema ({ type: Object }), the import util, and resetProgress all use an object/map — so every save hit !Array.isArray({...}) and returned 400, and progress was silently lost (kept only in localStorage). Validate it as a plain object instead. Fixes #1727 --- backend/controllers/userSheetProgressController.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/controllers/userSheetProgressController.js b/backend/controllers/userSheetProgressController.js index 3cdd267b..76c2bfc6 100644 --- a/backend/controllers/userSheetProgressController.js +++ b/backend/controllers/userSheetProgressController.js @@ -60,10 +60,15 @@ exports.saveProgress = async (req, res) => { }); } - if (completedTopics !== undefined && !Array.isArray(completedTopics)) { + if ( + completedTopics !== undefined && + (typeof completedTopics !== "object" || + completedTopics === null || + Array.isArray(completedTopics)) + ) { return res.status(400).json({ success: false, - error: "Invalid completedTopics field, must be an array", + error: "Invalid completedTopics field, must be an object", }); } From 200d7c236c52bb22cf49f988d2bb56ee4d73f8df Mon Sep 17 00:00:00 2001 From: vedant7007 Date: Tue, 11 Aug 2026 20:04:02 +0530 Subject: [PATCH 04/47] refine: validate completedTopics values are booleans (match record contract) Per review: the object check accepted any non-null object, so { "0-0-0": "true" } (string value) passed. Also require every value to be a boolean, matching the Zod z.record(z.string(), z.boolean()) contract and the map/{key:bool} shape. --- backend/controllers/userSheetProgressController.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/controllers/userSheetProgressController.js b/backend/controllers/userSheetProgressController.js index 76c2bfc6..c498990b 100644 --- a/backend/controllers/userSheetProgressController.js +++ b/backend/controllers/userSheetProgressController.js @@ -64,11 +64,15 @@ exports.saveProgress = async (req, res) => { completedTopics !== undefined && (typeof completedTopics !== "object" || completedTopics === null || - Array.isArray(completedTopics)) + Array.isArray(completedTopics) || + Object.values(completedTopics).some( + (value) => typeof value !== "boolean" + )) ) { return res.status(400).json({ success: false, - error: "Invalid completedTopics field, must be an object", + error: + "Invalid completedTopics field, must be an object of boolean flags", }); } From 3ac006d8ced19098c4ded47ae134d5d8af81188b Mon Sep 17 00:00:00 2001 From: tmdeveloper007 Date: Wed, 12 Aug 2026 15:36:39 +0000 Subject: [PATCH 05/47] feat : added AI interview question keyword extractor --- .../AIInterviewQuestionKeywordExtractor.jsx | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 frontend/src/pages/AIInterviewQuestionKeywordExtractor/AIInterviewQuestionKeywordExtractor.jsx diff --git a/frontend/src/pages/AIInterviewQuestionKeywordExtractor/AIInterviewQuestionKeywordExtractor.jsx b/frontend/src/pages/AIInterviewQuestionKeywordExtractor/AIInterviewQuestionKeywordExtractor.jsx new file mode 100644 index 00000000..d9ecbf04 --- /dev/null +++ b/frontend/src/pages/AIInterviewQuestionKeywordExtractor/AIInterviewQuestionKeywordExtractor.jsx @@ -0,0 +1,173 @@ +import React, { useState } from "react"; +import { + Tag, + Search, + Brain, + Layers, + Zap, + BookOpen, + ChevronRight, + TrendingUp, + Target, +} from "lucide-react"; + +const AIInterviewQuestionKeywordExtractor = () => { + const [inputQuestion, setInputQuestion] = useState("How would you design a scalable microservices architecture using Kubernetes and handle service discovery in a distributed system?"); + + const stats = { totalKeywords: 8, technicalDepth: 82, breadthScore: 65 }; + + const keywords = [ + { term: "scalable", category: "Concept", score: 95, color: "violet" }, + { term: "microservices", category: "Technical", score: 90, color: "blue" }, + { term: "Kubernetes", category: "Tool", score: 88, color: "blue" }, + { term: "architecture", category: "Domain", score: 85, color: "green" }, + { term: "service discovery", category: "Technical", score: 82, color: "blue" }, + { term: "distributed system", category: "Technical", score: 80, color: "blue" }, + { term: "scalability", category: "Concept", score: 78, color: "violet" }, + { term: "containerization", category: "Concept", score: 65, color: "violet" }, + ]; + + const questionIntent = { primary: "System Design", secondary: "Infrastructure", complexity: "Advanced", assessmentType: "Problem Solving & Architecture" }; + + const followUpQuestions = [ + "How would you handle network partitions and eventual consistency?", + "What monitoring and observability tools would you use at this scale?", + "How would you approach database selection for each microservice?", + "Describe your strategy for API versioning and backward compatibility.", + ]; + + const getCategoryBadge = (category) => { + if (category === "Technical") return "bg-blue-100 text-blue-700 dark:bg-blue-900/20 dark:text-blue-400"; + if (category === "Tool") return "bg-violet-100 text-violet-700 dark:bg-violet-900/20 dark:text-violet-400"; + if (category === "Concept") return "bg-green-100 text-green-700 dark:bg-green-900/20 dark:text-green-400"; + return "bg-amber-100 text-amber-700 dark:bg-amber-900/20 dark:text-amber-400"; + }; + + const getScoreColor = (score) => { + if (score >= 80) return "text-green-600"; + if (score >= 60) return "text-amber-500"; + return "text-red-500"; + }; + + const getBarColor = (color) => { + if (color === "violet") return "bg-gradient-to-r from-violet-500 to-purple-600"; + if (color === "blue") return "bg-gradient-to-r from-blue-500 to-indigo-600"; + if (color === "green") return "bg-gradient-to-r from-green-500 to-emerald-600"; + return "bg-gradient-to-r from-amber-500 to-orange-500"; + }; + + return ( +
+
+
+
+ +
+
+

AI Interview Question Keyword Extractor

+

Paste any interview question to extract key technical terms, understand the question intent, and identify what skills are being assessed.

+
+
+ +
+ {[ + { icon: , label: "Total Keywords", value: stats.totalKeywords }, + { icon: , label: "Technical Depth", value: `${stats.technicalDepth}%` }, + { icon: , label: "Breadth Score", value: `${stats.breadthScore}%` }, + ].map((item, i) => ( +
+ {item.icon} +

{item.label}

+

{item.value}

+
+ ))} +
+ +
+

AI Keyword Extraction Analysis

+

The AI extracts and categorizes technical keywords, domain terms, and important concepts from interview questions. Understanding the keywords helps you prepare targeted, specific answers that demonstrate deep knowledge of each topic.

+
+ +
+

Enter Interview Question

+