From 82081c7bde8607cbc2feaeef95014dd40a85fedd Mon Sep 17 00:00:00 2001 From: Suvam-paul145 Date: Fri, 27 Feb 2026 21:31:35 +0530 Subject: [PATCH 1/4] feat: Add Advanced Password Strength Meter using zxcvbn - Created passwordStrengthMeter.tsx component with advanced password analysis - Uses zxcvbn library for realistic entropy-based strength assessment - Displays color-coded strength meter (Very Weak to Very Strong) - Shows detailed crack time estimates for different attack scenarios - Provides warnings and suggestions for password improvement - Includes visibility toggle, copy, and clear functionality - Added comprehensive component configuration to developmentToolsConstant.tsx - Registered component and routes in constants.tsx - Added zxcvbn and @types/zxcvbn dependencies to package.json - Full TypeScript typing with proper null checks - Matches project styling and UI patterns Closes #19 --- .../passwordStrengthMeter.tsx | 370 +++++++++++++ app/libs/constants.tsx | 14 + app/libs/developmentToolsConstant.tsx | 114 ++++ package-lock.json | 503 +----------------- package.json | 4 +- 5 files changed, 527 insertions(+), 478 deletions(-) create mode 100644 app/components/developmentToolsComponent/passwordStrengthMeter.tsx diff --git a/app/components/developmentToolsComponent/passwordStrengthMeter.tsx b/app/components/developmentToolsComponent/passwordStrengthMeter.tsx new file mode 100644 index 0000000..c35651a --- /dev/null +++ b/app/components/developmentToolsComponent/passwordStrengthMeter.tsx @@ -0,0 +1,370 @@ +"use client"; +import React, { useCallback, useMemo, useState } from "react"; +import zxcvbn from "zxcvbn"; +import { toast } from "react-toastify"; +import DevelopmentToolsStyles from "../../developmentToolsStyles.module.scss"; + +const PasswordStrengthMeter = () => { + const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + const [copied, setCopied] = useState(false); + + // Analyze password strength using zxcvbn + const analysis = useMemo(() => { + if (!password) return null; + return zxcvbn(password); + }, [password]); + + // Get strength level and color + const getStrengthInfo = useCallback( + (score: number) => { + switch (score) { + case 0: + return { label: "Very Weak", color: "#ef4444", percentage: 20 }; // Red + case 1: + return { label: "Weak", color: "#f97316", percentage: 40 }; // Orange + case 2: + return { label: "Fair", color: "#eab308", percentage: 60 }; // Yellow + case 3: + return { label: "Good", color: "#84cc16", percentage: 80 }; // Light Green + case 4: + return { label: "Very Strong", color: "#22c55e", percentage: 100 }; // Green + default: + return { label: "Neutral", color: "#6b7280", percentage: 0 }; // Gray + } + }, + [] + ); + + // Format crack time for display + const formatCrackTime = useCallback((seconds: number): string => { + if (seconds === Infinity || !isFinite(seconds)) { + return "Centuries+"; + } + + if (seconds < 1) return "Less than a second"; + if (seconds < 60) return Math.round(seconds) + " seconds"; + if (seconds < 3600) return Math.round(seconds / 60) + " minutes"; + if (seconds < 86400) return Math.round(seconds / 3600) + " hours"; + if (seconds < 2592000) return Math.round(seconds / 86400) + " days"; + if (seconds < 31536000) return Math.round(seconds / 2592000) + " months"; + return Math.round(seconds / 31536000) + " years"; + }, []); + + // Get crack time estimates + const getCrackTimes = useCallback((): CrackTime | null => { + if (!analysis) return null; + + const crackTimesSeconds = analysis.crack_times_seconds; + + return { + onlineThrottling100perHour: formatCrackTime( + typeof crackTimesSeconds.online_throttling_100_per_hour === "number" + ? crackTimesSeconds.online_throttling_100_per_hour + : 0 + ), + onlineNoThrottling10perSecond: formatCrackTime( + typeof crackTimesSeconds.online_no_throttling_10_per_second === "number" + ? crackTimesSeconds.online_no_throttling_10_per_second + : 0 + ), + offlineSlowHashing1e4perSecond: formatCrackTime( + typeof crackTimesSeconds.offline_slow_hashing_1e4_per_second === + "number" + ? crackTimesSeconds.offline_slow_hashing_1e4_per_second + : 0 + ), + offlineFastHashing1e10perSecond: formatCrackTime( + typeof crackTimesSeconds.offline_fast_hashing_1e10_per_second === + "number" + ? crackTimesSeconds.offline_fast_hashing_1e10_per_second + : 0 + ), + }; + }, [analysis, formatCrackTime]); + + interface CrackTime { + onlineThrottling100perHour: string; + onlineNoThrottling10perSecond: string; + offlineSlowHashing1e4perSecond: string; + offlineFastHashing1e10perSecond: string; + } + + // Handle copy to clipboard + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(password); + setCopied(true); + toast.success("Password copied to clipboard!"); + setTimeout(() => setCopied(false), 2000); + } catch (_err) { + toast.error("Failed to copy password"); + } + }; + + // Handle clear + const handleClear = () => { + setPassword(""); + setShowPassword(false); + setCopied(false); + }; + + const strengthInfo = + analysis && analysis.score !== undefined + ? getStrengthInfo(analysis.score) + : null; + const crackTimes = getCrackTimes(); + + return ( +
+
+
+
+
+ {/* Password Input Section */} +
+
+ +
+ setPassword(e.target.value)} + placeholder="Type your password to check strength..." + className={`${DevelopmentToolsStyles.scrollbar} w-full bg-black !border !border-[#222222] p-4 pr-12 rounded-xl focus:outline-none focus:border-[#444444] text-white`} + /> + +
+
+ + {/* Password Strength Meter */} + {password && strengthInfo && ( + <> + {/* Strength Bar */} +
+
+ + + {strengthInfo.label} + +
+
+
+
+
+ + {/* Detailed Analytics */} + {crackTimes && ( +
+

+ Crack Time Estimates +

+
+
+

+ Online Attack (Throttled) +

+

+ {crackTimes.onlineThrottling100perHour} +

+
+
+

+ Online Attack (Unthrottled) +

+

+ {crackTimes.onlineNoThrottling10perSecond} +

+
+
+

+ Offline Attack (Slow Hashing) +

+

+ {crackTimes.offlineSlowHashing1e4perSecond} +

+
+
+

+ Offline Attack (Fast Hashing) +

+

+ {crackTimes.offlineFastHashing1e10perSecond} +

+
+
+
+ )} + + {/* Warnings */} + {analysis && analysis.feedback.warning && ( +
+

⚠️ Warning

+

{analysis.feedback.warning}

+
+ )} + + {/* Suggestions */} + {analysis && analysis.feedback.suggestions && + analysis.feedback.suggestions.length > 0 && ( +
+

💡 Suggestions

+
    + {analysis.feedback.suggestions.map( + (suggestion: string, idx: number) => ( +
  • {suggestion}
  • + ) + )} +
+
+ )} + + {/* Entropy Info */} + {analysis && ( +
+

+ Entropy Analysis +

+
+
+

Entropy Bits

+

+ {analysis.guesses_log10.toFixed(2)} +

+
+
+

+ Estimated Guesses +

+

+ {analysis.guesses + .toExponential(2) + .replace(/e\+/, "e")} +

+
+
+
+ )} + + {/* Sequence Analysis */} + {analysis && analysis.sequence.length > 0 && ( +
+

+ Pattern Breakdown +

+
+ {analysis.sequence.slice(0, 5).map((match: any, idx: number) => ( +
+

+ {match.pattern || "Pattern"} +

+

+ {match.token} +

+
+ ))} + {analysis.sequence.length > 5 && ( +

+ +{analysis.sequence.length - 5} more patterns +

+ )} +
+
+ )} + + )} + + {/* Action Buttons */} + {password && ( +
+ + +
+ )} + + {/* Empty State */} + {!password && ( +
+

+ Enter a password to see strength analysis +

+
+ )} +
+
+
+
+
+
+ ); +}; + +export default PasswordStrengthMeter; diff --git a/app/libs/constants.tsx b/app/libs/constants.tsx index c51e71e..f1c416c 100644 --- a/app/libs/constants.tsx +++ b/app/libs/constants.tsx @@ -125,6 +125,7 @@ import MorseCodeTranslator from '../components/developmentToolsComponent/morseCo import NumbersToWordsConverter from '../components/developmentToolsComponent/numbersToWordsConverter'; import OctalToBinaryConverter from '../components/developmentToolsComponent/octalToBinaryConverter'; import OctalToDecimalConverter from '../components/developmentToolsComponent/octalToDecimalConverter'; +import PasswordStrengthMeter from '../components/developmentToolsComponent/passwordStrengthMeter'; import PHPFormatter from '../components/developmentToolsComponent/phpFormatter'; import PlaceholderImageGenerator from '../components/developmentToolsComponent/placeholderImageGenerator'; import PxToRemConverter from '../components/developmentToolsComponent/pxToRemConverter'; @@ -1589,6 +1590,14 @@ export const developmentToolsCategoryContent: any = { description: 'Convert HTML to Jade.', }, ], + Category176: [ + { + url: '/password-strength-meter', + title: 'Password Strength Meter', + description: + 'Check your password strength using advanced entropy analysis with real crack-time estimates.', + }, + ], }; export const PATHS = { @@ -1621,6 +1630,7 @@ export const PATHS = { RANDOM_USERNAME_GENERATOR: '/random-username-generator', SORT_NUMBER: '/sort-number', SORT_WORD: '/sort-word', + PASSWORD_STRENGTH_METER: '/password-strength-meter', PHONE_NUMBER_EXTRACTOR: '/phone-number-extractor', REVERSE_TEXT_GENERATOR: '/reverse-text-generator', WORD_TO_NUMBER: '/word-to-number', @@ -2466,6 +2476,10 @@ export const developmentToolsRoutes = [ path: PATHS.HTML_TO_JADE, component: , }, + { + path: PATHS.PASSWORD_STRENGTH_METER, + component: , + }, ]; // lorem ipsum text diff --git a/app/libs/developmentToolsConstant.tsx b/app/libs/developmentToolsConstant.tsx index aea9220..e30f030 100644 --- a/app/libs/developmentToolsConstant.tsx +++ b/app/libs/developmentToolsConstant.tsx @@ -3656,6 +3656,120 @@ export const DEVELOPMENTTOOLS: any = { og_image: '/images/og-images/Cover.png', }, }, + [`password-strength-meter`]: { + hero_section: { + title: 'Advanced Password Strength Meter', + description: + 'Check your password strength using advanced entropy analysis. Get realistic crack-time estimates, warnings, and suggestions for creating stronger passwords using the zxcvbn algorithm.', + }, + development_tools_list: [ + { tool: 'Random Password Generator', url: PATHS.RANDOM_PASSWORD_GENERATOR }, + { tool: 'Bcrypt Generator', url: PATHS.BCRYPT_GENERATOR }, + { tool: 'Text to HTML Entities', url: PATHS.TEXT_TO_HTML_ENTITIES_CONVERTOR }, + { tool: 'Character Count', url: PATHS.CHARACTER_COUNT_TOOL }, + { tool: 'MD5 Generator', url: PATHS.RANDOM_USERNAME_GENERATOR }, + { tool: 'Base64 Encoder', url: PATHS.BASE64_ENCODER }, + ], + development_tools_about_details: { + about_title: 'What is the Password Strength Meter?', + about_description: [ + { + description: + 'The Password Strength Meter is an advanced security tool that analyzes password strength using entropy-based calculations. Unlike simple pattern matching (e.g., "must contain numbers"), this tool uses the industry-standard zxcvbn algorithm to provide realistic password strength assessments.', + }, + { + description: + 'The tool calculates actual crack time estimates for different attack scenarios (online throttled, online unthrottled, offline slow hashing, and offline fast hashing). It also provides actionable warnings and suggestions to improve your password security.', + }, + { + description: + 'Use this tool to verify password security before setting critical account credentials, validate password policies, or educate users about common password weaknesses. All analysis is done locally in your browser with no data stored or transmitted.', + }, + ], + }, + development_tools_steps_guide: { + guide_title: 'How to Use the Password Strength Meter', + guide_description: 'Follow these steps to analyze your password strength:', + steps: [ + { + step_key: 'Step 1:', + step_title: 'Enter Your Password', + step_description: + 'Type or paste your password in the input field. Use the visibility toggle button (eye icon) to show or hide your password as you type.', + }, + { + step_key: 'Step 2:', + step_title: 'View Strength Assessment', + step_description: + 'Watch the color-coded strength meter: Red (Very Weak) → Orange (Weak) → Yellow (Fair) → Light Green (Good) → Green (Very Strong). The meter updates in real-time as you type.', + }, + { + step_key: 'Step 3:', + step_title: 'Review Crack Time Estimates', + step_description: + 'Check how long it would take attackers to crack your password under different scenarios: throttled online attacks, unthrottled online attacks, slow hashing, and fast hashing.', + }, + { + step_key: 'Step 4:', + step_title: 'Address Warnings and Suggestions', + step_description: + 'If present, read the warning messages (like "common password" or "repeated characters") and follow the suggestions to strengthen your password.', + }, + { + step_key: 'Step 5:', + step_title: 'Copy or Clear', + step_description: + 'Use the "Copy Password" button to copy your password to clipboard, or "Clear" to reset and try a different password.', + }, + ], + }, + development_tools_how_use: { + how_use_title: 'Use Cases for the Password Strength Meter', + how_use_description: + 'This tool is useful for various security-related purposes:', + point: [ + { + title: 'Personal Account Security', + description: + 'Before creating important account passwords (email, banking, social media), use this tool to ensure your passwords are strong and resistant to cracking attempts.', + }, + { + title: 'Corporate Password Policy Validation', + description: + 'Organizations can use this tool to help employees understand password complexity requirements and create stronger credentials that comply with security policies.', + }, + { + title: 'Security Awareness Training', + description: + 'Security teams can use the tool in training sessions to demonstrate password weaknesses and help employees understand why certain passwords are vulnerable.', + }, + { + title: 'System Administration', + description: + 'IT administrators can validate password policies and ensure user-created passwords meet organizational security standards.', + }, + { + title: 'Educational Purposes', + description: + 'Computer science and cybersecurity educators can teach students about password entropy, hash algorithms, and realistic security threats.', + }, + { + title: 'Software Development Testing', + description: + 'Developers building authentication systems can test their password strength validation logic against industry standards.', + }, + ], + }, + meta_data: { + meta_title: 'Password Strength Meter - Advanced Security Analysis Tool', + meta_description: + 'Free online password strength meter using zxcvbn algorithm. Get realistic crack-time estimates, warnings, and suggestions for stronger passwords. Powered by entropy-based analysis.', + og_title: 'Password Strength Meter - Advanced Security Analysis Tool', + og_description: + 'Check password strength with advanced entropy analysis. Real crack-time estimates and actionable security suggestions included.', + og_image: '/images/og-images/Cover.png', + }, + }, [`phone-number-extractor`]: { hero_section: { title: 'Phone Number Extractor Online', diff --git a/package-lock.json b/package-lock.json index ec0383b..90a20c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,8 @@ "react-responsive": "10.0.0", "react-toastify": "11.0.3", "sass": "1.75.0", - "turndown": "7.2.0" + "turndown": "7.2.0", + "zxcvbn": "^4.4.2" }, "devDependencies": { "@semantic-release/changelog": "^6.0.3", @@ -48,12 +49,17 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/zxcvbn": "^4.4.5", "eslint": "^8", "eslint-config-next": "14.2.1", "postcss": "^8", "semantic-release": "^23.0.8", "tailwindcss": "^3.4.1", "typescript": "^5" + }, + "engines": { + "node": ">=20.8.0", + "npm": ">=10.0.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3663,35 +3669,6 @@ "integrity": "sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==", "license": "MIT" }, - "node_modules/@types/eslint": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", - "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", - "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "license": "MIT", - "peer": true - }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -3770,12 +3747,14 @@ "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", + "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.2.78", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.78.tgz", "integrity": "sha512-qOwdPnnitQY4xKlKayt42q5W5UQrSHjgoXNVEtxeqdITJ99k4VXJOP3vt8Rkm9HmgJpH50UNU+rlqfkfWOqp0A==", + "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -3819,6 +3798,13 @@ "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==", "license": "MIT" }, + "node_modules/@types/zxcvbn": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/@types/zxcvbn/-/zxcvbn-4.4.5.tgz", + "integrity": "sha512-FZJgC5Bxuqg7Rhsm/bx6gAruHHhDQ55r+s0JhDh8CQ16fD7NsJJ+p8YMMQDhSQoIrSmjpqqYWA96oQVMNkjRyA==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/parser": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", @@ -3960,187 +3946,12 @@ "dev": true, "license": "ISC" }, - "node_modules/@webassemblyjs/ast": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", - "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", - "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", - "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", - "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", - "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.13.2", - "@webassemblyjs/helper-api-error": "1.13.2", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", - "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", - "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/wasm-gen": "1.14.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", - "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", - "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", - "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", - "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/helper-wasm-section": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-opt": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1", - "@webassemblyjs/wast-printer": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", - "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", - "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-buffer": "1.14.1", - "@webassemblyjs/wasm-gen": "1.14.1", - "@webassemblyjs/wasm-parser": "1.14.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", - "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@webassemblyjs/helper-api-error": "1.13.2", - "@webassemblyjs/helper-wasm-bytecode": "1.13.2", - "@webassemblyjs/ieee754": "1.13.2", - "@webassemblyjs/leb128": "1.13.2", - "@webassemblyjs/utf8": "1.13.2" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", - "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@webassemblyjs/ast": "1.14.1", - "@xtuc/long": "4.2.2" - } - }, "node_modules/@xstate/fsm": { "version": "1.6.5", "resolved": "https://registry.npmjs.org/@xstate/fsm/-/fsm-1.6.5.tgz", "integrity": "sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==", "license": "MIT" }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "license": "Apache-2.0", - "peer": true - }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -4153,19 +3964,6 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-phases": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", - "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "acorn": "^8.14.0" - } - }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -5099,16 +4897,6 @@ "node": ">= 6" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", - "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.0" - } - }, "node_modules/class-validator": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz", @@ -5961,16 +5749,6 @@ "node": ">=6.0.0" } }, - "node_modules/dompurify": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", - "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", - "license": "(MPL-2.0 OR Apache-2.0)", - "peer": true, - "optionalDependencies": { - "@types/trusted-types": "^2.0.7" - } - }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -6073,6 +5851,7 @@ "version": "5.19.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -6364,13 +6143,6 @@ "node": ">= 0.4" } }, - "node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "license": "MIT", - "peer": true - }, "node_modules/es-object-atoms": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", @@ -6905,16 +6677,6 @@ "node": ">=0.10.0" } }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -7528,13 +7290,6 @@ "node": ">=10.13.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "license": "BSD-2-Clause", - "peer": true - }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -8809,6 +8564,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, "license": "MIT" }, "node_modules/json-schema": { @@ -9038,20 +8794,6 @@ "node": ">=4" } }, - "node_modules/loader-runner": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", - "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6.11.5" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/loader-utils": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", @@ -9380,29 +9122,6 @@ "node": ">=16" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "peer": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -9487,30 +9206,6 @@ "node": "*" } }, - "node_modules/monaco-editor": { - "version": "0.55.1", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", - "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", - "license": "MIT", - "peer": true, - "dependencies": { - "dompurify": "3.2.7", - "marked": "14.0.0" - } - }, - "node_modules/monaco-editor/node_modules/marked": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", - "license": "MIT", - "peer": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -9577,6 +9272,7 @@ "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, "license": "MIT" }, "node_modules/nerf-dart": { @@ -16330,6 +16026,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -17029,20 +16726,6 @@ "node": ">= 0.10" } }, - "node_modules/watchpack": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", - "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", - "license": "MIT", - "peer": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/web-worker": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", @@ -17056,146 +16739,6 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", "license": "BSD-2-Clause" }, - "node_modules/webpack": { - "version": "5.105.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz", - "integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.8", - "@types/json-schema": "^7.0.15", - "@webassemblyjs/ast": "^1.14.1", - "@webassemblyjs/wasm-edit": "^1.14.1", - "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", - "acorn-import-phases": "^1.0.3", - "browserslist": "^4.28.1", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.19.0", - "es-module-lexer": "^2.0.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.11", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.3.1", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^4.3.3", - "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", - "watchpack": "^2.5.1", - "webpack-sources": "^3.3.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-sources": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", - "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "license": "BSD-2-Clause", - "peer": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", - "peer": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "peer": true - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", - "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/whatwg-url": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", @@ -17837,6 +17380,12 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zxcvbn": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz", + "integrity": "sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==", + "license": "MIT" } } } diff --git a/package.json b/package.json index ffbbfb0..276bdc2 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,8 @@ "react-responsive": "10.0.0", "react-toastify": "11.0.3", "sass": "1.75.0", - "turndown": "7.2.0" + "turndown": "7.2.0", + "zxcvbn": "^4.4.2" }, "devDependencies": { "@semantic-release/changelog": "^6.0.3", @@ -74,6 +75,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/zxcvbn": "^4.4.5", "eslint": "^8", "eslint-config-next": "14.2.1", "postcss": "^8", From 637b63d48f8309d55e40c69526e5326895c59bac Mon Sep 17 00:00:00 2001 From: Suvam-paul145 Date: Sat, 28 Feb 2026 14:18:49 +0530 Subject: [PATCH 2/4] Robust JSON Schema Validation --- .../jsonValidator.tsx | 681 +++++++++--------- package-lock.json | 171 +++-- package.json | 2 + 3 files changed, 453 insertions(+), 401 deletions(-) diff --git a/app/components/developmentToolsComponent/jsonValidator.tsx b/app/components/developmentToolsComponent/jsonValidator.tsx index 88533e7..01567bb 100644 --- a/app/components/developmentToolsComponent/jsonValidator.tsx +++ b/app/components/developmentToolsComponent/jsonValidator.tsx @@ -1,6 +1,11 @@ "use client"; import React, { useState } from "react"; +import Ajv from "ajv"; +import addFormats from "ajv-formats"; + +const ajv = new Ajv({ allErrors: true, strict: false }); +addFormats(ajv); interface ValidationResult { isValid: boolean; @@ -178,47 +183,15 @@ const JsonValidator = () => { const json = JSON.parse(jsonString); const schema = JSON.parse(schemaString); - // Basic schema validation (simplified version) - if (schema.type) { - const actualType = Array.isArray(json) ? "array" : typeof json; - if (actualType !== schema.type) { - errors.push( - `Type mismatch: expected ${schema.type}, got ${actualType}` - ); - } - } + const validate = ajv.compile(schema); + const valid = validate(json); - if (schema.required && Array.isArray(schema.required)) { - schema.required.forEach((field: string) => { - if (!(field in json)) { - errors.push(`Required field missing: ${field}`); - } + if (!valid && validate.errors) { + validate.errors.forEach((err) => { + const path = err.instancePath ? err.instancePath.substring(1).replace(/\//g, ".") : "root"; + errors.push(`${path}: ${err.message}${err.params ? ` (${JSON.stringify(err.params)})` : ""}`); }); } - - if ( - schema.properties && - typeof json === "object" && - !Array.isArray(json) - ) { - Object.entries(schema.properties).forEach( - ([key, prop]: [string, any]) => { - if (key in json) { - const value = json[key]; - if (prop.type) { - const actualType = Array.isArray(value) - ? "array" - : typeof value; - if (actualType !== prop.type) { - errors.push( - `Property '${key}' type mismatch: expected ${prop.type}, got ${actualType}` - ); - } - } - } - } - ); - } } catch (error: any) { errors.push(`Schema validation error: ${error.message}`); } @@ -302,14 +275,71 @@ const JsonValidator = () => { const sampleSchemas = { user: JSON.stringify( { + $schema: "http://json-schema.org/draft-07/schema#", type: "object", - required: ["id", "name", "email"], + required: ["id", "name", "email", "address"], properties: { - id: { type: "number" }, - name: { type: "string" }, - email: { type: "string" }, - age: { type: "number" }, + id: { type: "integer", minimum: 1 }, + name: { type: "string", minLength: 2 }, + email: { type: "string", format: "email" }, + age: { type: "integer", minimum: 0, maximum: 120 }, isActive: { type: "boolean" }, + address: { + type: "object", + required: ["street", "city"], + properties: { + street: { type: "string" }, + city: { type: "string" }, + zipCode: { type: "string", pattern: "^[0-9]{5}(-[0-9]{4})?$" }, + }, + }, + tags: { + type: "array", + items: { type: "string" }, + uniqueItems: true, + }, + }, + }, + null, + 2 + ), + advanced: JSON.stringify( + { + $schema: "http://json-schema.org/draft-07/schema#", + title: "Advanced Schema", + definitions: { + address: { + type: "object", + properties: { + street: { type: "string" }, + city: { type: "string" }, + }, + }, + }, + type: "object", + properties: { + shipping_address: { $ref: "#/definitions/address" }, + billing_address: { $ref: "#/definitions/address" }, + contact: { + oneOf: [ + { + type: "object", + properties: { + type: { const: "email" }, + value: { type: "string", format: "email" }, + }, + required: ["type", "value"], + }, + { + type: "object", + properties: { + type: { const: "phone" }, + value: { type: "string", pattern: "^\\+[1-9]\\d{1,14}$" }, + }, + required: ["type", "value"], + }, + ], + }, }, }, null, @@ -320,10 +350,10 @@ const JsonValidator = () => { type: "object", required: ["id", "title", "price"], properties: { - id: { type: "string" }, + id: { type: "string", pattern: "^PRD-[0-9]{4}$" }, title: { type: "string" }, - price: { type: "number" }, - category: { type: "string" }, + price: { type: "number", exclusiveMinimum: 0 }, + category: { enum: ["electronics", "clothing", "home", "books"] }, inStock: { type: "boolean" }, }, }, @@ -337,320 +367,317 @@ const JsonValidator = () => {
- {/* Main Content */} -
- {/* Input Section */} -
-
-

Enter Value

-
- - - -
-
-