quantum integration - #5
ssantoshhhhh wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Introduces a “quantum” security integration across backend auth/token issuance and parts of the citizen UI, including a health/status endpoint and usage of generated entropy for identifiers/signatures.
Changes:
- Add
quantumServiceand expose/api/auth/quantum-statusfor frontend display. - Embed a “quantum fingerprint” (
qf) into citizen and police JWTs; use “quantum entropy” for complaint tracking IDs and audit signatures. - Update citizen UI to fetch/display quantum status and adjust loading/status copy; includes various formatting-only refactors.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/pages/citizen/LoginPage.jsx | Fetches /api/auth/quantum-status, shows a quantum badge, and changes Aadhaar OTP loading UI text/spinner |
| frontend/src/pages/citizen/ComplaintPage.jsx | Adds quantum status fetch (currently unused) and updates some UI/security copy plus formatting |
| backend/src/services/quantumService.js | New service providing “quantum entropy” generation and health metadata |
| backend/src/routes/policeAuth.js | Adds qf claim to police access/refresh JWTs via async token generation |
| backend/src/routes/complaints.js | Uses quantum entropy for tracking ID seed and forensics “audit signature” keying |
| backend/src/routes/auth.js | Adds qf to citizen JWTs and exposes GET /quantum-status |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const [quantumStatus, setQuantumStatus] = useState(null); | ||
|
|
||
| useEffect(() => { | ||
| const checkQuantum = async () => { | ||
| try { | ||
| const res = await api.get("/api/auth/quantum-status"); | ||
| setQuantumStatus(res.data); | ||
| } catch (err) { | ||
| console.error("Quantum Status Error", err); | ||
| } | ||
| }; | ||
| checkQuantum(); | ||
| }, []); | ||
|
|
||
| useEffect(() => { |
There was a problem hiding this comment.
quantumStatus is fetched on mount but never referenced anywhere else in this component (only state initialization + API call). This adds an extra network request and state updates for no effect; either render the status somewhere or remove the state/effect until it’s needed.
| const [quantumStatus, setQuantumStatus] = useState(null); | |
| useEffect(() => { | |
| const checkQuantum = async () => { | |
| try { | |
| const res = await api.get("/api/auth/quantum-status"); | |
| setQuantumStatus(res.data); | |
| } catch (err) { | |
| console.error("Quantum Status Error", err); | |
| } | |
| }; | |
| checkQuantum(); | |
| }, []); | |
| useEffect(() => { | |
| useEffect(() => { |
| aiData?.location || activeStation | ||
| ? `${activeStation.stationName}, ${activeStation.district}` | ||
| : "Detected", |
There was a problem hiding this comment.
The receipt location expression has a precedence issue: aiData?.location || activeStation ? ... : ... is evaluated as (aiData?.location || activeStation) ? ... : ..., which will ignore a non-empty aiData.location and always choose the station string when aiData.location is truthy. Wrap the ternary in parentheses so aiData.location properly takes precedence (or restructure the conditional).
| aiData?.location || activeStation | |
| ? `${activeStation.stationName}, ${activeStation.district}` | |
| : "Detected", | |
| aiData?.location || | |
| (activeStation | |
| ? `${activeStation.stationName}, ${activeStation.district}` | |
| : "Detected"), |
| _simulateQuantumHadamard(bitsCount) { | ||
| let result = ''; | ||
| for (let i = 0; i < bitsCount; i++) { | ||
| const bit = Math.random() < 0.5 ? '0' : '1'; | ||
| result += bit; | ||
| } | ||
| return require('crypto').createHash('sha256').update(result).digest('hex'); | ||
| } |
There was a problem hiding this comment.
_simulateQuantumHadamard uses Math.random() to generate bits, but the output is used for security-sensitive values (JWT fingerprint, tracking ID salt, audit HMAC key). Math.random() is not cryptographically secure in Node and should not be used for entropy; use crypto.randomBytes(...) (or crypto.webcrypto.getRandomValues) for the simulator mode.
| async getQuantumEntropy(bitsCount = 256) { | ||
| const start = Date.now(); | ||
| const entropy = this._simulateQuantumHadamard(bitsCount); | ||
| const duration = Date.now() - start; | ||
|
|
||
| logger.info(`⚛️ QUANTUM-ENTROPY: Generated ${bitsCount} bits using ${this.status.toUpperCase()} mode (${duration}ms)`); | ||
| return entropy; | ||
| } | ||
|
|
||
| _simulateQuantumHadamard(bitsCount) { | ||
| let result = ''; | ||
| for (let i = 0; i < bitsCount; i++) { |
There was a problem hiding this comment.
getQuantumEntropy(bitsCount) logs "Generated X bits" but _simulateQuantumHadamard always returns a SHA-256 hex digest (fixed length) regardless of bitsCount. This is misleading for callers and makes the bitsCount parameter effectively not control the returned entropy size; consider returning raw bytes of the requested size (or rename the parameter / adjust the log + docs to match what’s actually returned).
| async getQuantumEntropy(bitsCount = 256) { | |
| const start = Date.now(); | |
| const entropy = this._simulateQuantumHadamard(bitsCount); | |
| const duration = Date.now() - start; | |
| logger.info(`⚛️ QUANTUM-ENTROPY: Generated ${bitsCount} bits using ${this.status.toUpperCase()} mode (${duration}ms)`); | |
| return entropy; | |
| } | |
| _simulateQuantumHadamard(bitsCount) { | |
| let result = ''; | |
| for (let i = 0; i < bitsCount; i++) { | |
| async getQuantumEntropy(samplesCount = 256) { | |
| const start = Date.now(); | |
| const entropy = this._simulateQuantumHadamard(samplesCount); | |
| const duration = Date.now() - start; | |
| const producedBits = typeof entropy === 'string' ? entropy.length * 4 : 0; | |
| logger.info( | |
| `⚛️ QUANTUM-ENTROPY: Generated ${producedBits} output bits from ${samplesCount} Hadamard samples using ${this.status.toUpperCase()} mode (${duration}ms)` | |
| ); | |
| return entropy; | |
| } | |
| _simulateQuantumHadamard(samplesCount) { | |
| let result = ''; | |
| for (let i = 0; i < samplesCount; i++) { |
| const axios = require('axios'); | ||
| const { logger } = require('../utils/logger'); | ||
|
|
||
| /** | ||
| * QUANTUM SERVICE | ||
| * Provides Quantum Random Number Generation (QRNG) and Post-Quantum Security layers. | ||
| * Supports: | ||
| * 1. LIVE IBM Quantum (Qiskit Runtime) | ||
| * 2. Local Quantum Simulator (Circuit-based JS simulation) | ||
| */ | ||
|
|
||
| const IBM_QUANTUM_API_KEY = process.env.IBM_QUANTUM_API_KEY; | ||
| const IBM_API_URL = 'https://auth.quantum-computing.ibm.com/api/api-token'; | ||
| const RUNTIME_BASE_URL = 'https://runtime-us-east.quantum-computing.ibm.com'; | ||
|
|
There was a problem hiding this comment.
axios and the IBM endpoint constants (IBM_QUANTUM_API_KEY, IBM_API_URL, RUNTIME_BASE_URL) are declared but unused in this module. If they’re placeholders, consider removing them until an IBM implementation is added (or add a minimal usage) to avoid dead code / potential lint failures.
| // Generate a 'Digital Audit Signature' for Forensics with Quantum Salt | ||
| const qsalt = await quantumService.getQuantumEntropy(64); | ||
| const auditSignature = crypto.createHmac('sha3-512', qsalt) | ||
| .update(`${trackingId}|${req.user.id}|${new Date().toISOString()}`) | ||
| .digest('hex'); |
There was a problem hiding this comment.
auditSignature is now computed as an HMAC keyed by qsalt, but qsalt is not persisted anywhere. That makes the value effectively a random hash that cannot be recomputed/verified later, which conflicts with the "Digital Audit Signature" / forensics intent. If you need verifiability, key the HMAC with a stable server secret and include qsalt as part of the message (or store qsalt alongside the signature).
| boxShadow: "0 0 10px #38bdf8", | ||
| }} | ||
| ></span> | ||
| QUANTUM PROTOCOL: {quantumStatus.status.toUpperCase()} |
There was a problem hiding this comment.
The new Quantum status badge contains user-facing copy ("QUANTUM PROTOCOL") that bypasses i18n, while the rest of the page uses t(...). Consider moving this string (and any derived formatting like "PROTOCOL") into translation keys so the banner is localized consistently.
| QUANTUM PROTOCOL: {quantumStatus.status.toUpperCase()} | |
| {t("login.quantumProtocolLabel")} {quantumStatus.status.toUpperCase()} |
| {loading ? ( | ||
| <div | ||
| style={{ | ||
| display: "flex", | ||
| alignItems: "center", | ||
| gap: "10px", | ||
| }} | ||
| > | ||
| <div className="spinner-small" /> | ||
| ENTANGLING... | ||
| </div> | ||
| ) : ( | ||
| t("login.getAadhaarOtp") | ||
| )} |
There was a problem hiding this comment.
The Aadhaar OTP button loading state now renders hardcoded text ("ENTANGLING...") instead of the existing localized t("login.requestingOtp"). This introduces an unlocalized UI string and removes an existing translation key; prefer keeping the translated loading label (or add a new i18n key if the copy must change).
No description provided.