feat(frontend): improve qr share and handshake flow - #11
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| useEffect(() => { | ||
| if (!profile?.cubid_id) { | ||
| return undefined; | ||
| } | ||
|
|
||
| const unsubscribe = subscribeToHandshake(profile.cubid_id, (payload) => { | ||
| setResult({ | ||
| targetCubid: payload.targetCubid, | ||
| viewerCubid: payload.viewerCubid, | ||
| challengeId: payload.challengeId, | ||
| expiresAt: payload.expiresAt, | ||
| overlaps: payload.overlaps, | ||
| verifiedAt: Date.now(), | ||
| }); | ||
| setHandshakeMessage("Handshake completed—opening shared overlaps…"); | ||
| router.push("/results"); | ||
| }); |
There was a problem hiding this comment.
Trusting unauthenticated Supabase broadcast for handshake completion
The share page subscribes to handshake:${profile.cubid_id} and immediately treats any handshake-complete broadcast as authoritative, storing the supplied overlaps and redirecting to /results. Because subscribeToHandshake (frontend/src/lib/handshake.ts) uses the public Supabase anon client and channel names are just the Cubid ID, any client with the anon key can broadcast a forged payload to the same channel. A malicious page can therefore spoof a handshake completion for another user and populate arbitrary overlap data. To avoid spoofing, verify the handshake server-side (e.g., fetch the overlaps again before redirecting) or use an unguessable per-challenge channel secured by Row Level Security.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull Request Overview
This pull request rebrands the application from "Peer Mapper" to "Trust Me Bro" and implements a real-time handshake notification system using Supabase Realtime channels. The changes enhance the QR code scanning experience with live camera preview and enable bidirectional handshake completion notifications between peers.
Key changes include:
- Introduction of a real-time handshake module using Supabase broadcast channels for peer-to-peer notifications
- Camera-based QR scanning with live preview, error handling, and retry mechanism
- Enhanced QR code display using the qrcode.react library with improved visual presentation
- Complete rebranding from "Peer Mapper" to "Trust Me Bro" across all UI components and documentation
Reviewed Changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Adds qrcode.react@4.2.0 dependency for QR code rendering |
| frontend/package.json | Includes qrcode.react package specification |
| frontend/src/lib/handshake.ts | New module implementing real-time handshake notifications via Supabase channels |
| frontend/src/components/QRScanner.tsx | Complete rewrite to implement camera preview with getUserMedia API |
| frontend/src/components/QRDisplay.tsx | Enhanced QR display using QRCodeSVG with improved styling and accessibility |
| frontend/src/components/AppHeader.tsx | Rebrand references from "Peer Mapper" to "Trust Me Bro" |
| frontend/src/components/AppFooter.tsx | Update copyright notice with new brand name |
| frontend/src/app/page.tsx | Update landing page content with new brand name |
| frontend/src/app/layout.tsx | Update page title metadata |
| frontend/src/app/(routes)/scan/my-qr/page.tsx | Add handshake subscription to receive completion notifications from peers |
| frontend/src/app/(routes)/scan/camera/page.tsx | Integrate handshake notification broadcasting and reorganize UI with collapsible dev tools |
| frontend/src/app/(routes)/profile/page.tsx | Add profile preview section with image error handling |
| frontend/src/app/(routes)/new-user/page.tsx | Update onboarding flow text and simplify redirect logic |
| frontend/tests/scan-qr-page.test.tsx | New test suite for QR page with handshake completion scenarios |
| frontend/tests/scan-camera-page.test.tsx | Update tests to include camera mock setup and handshake notification verification |
| frontend/tests/profile-page.test.tsx | New test suite for profile page preview functionality |
| frontend/tests/app-header.test.tsx | Update test expectations for rebranded header |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -1,7 +1,8 @@ | |||
| "use client"; | |||
|
|
|||
There was a problem hiding this comment.
[nitpick] There's an extra blank line here. This should be removed to maintain consistent spacing in the file.
| export function subscribeToHandshake( | ||
| targetCubid: string, | ||
| onComplete: (payload: HandshakeCompletion) => void, | ||
| ): () => void { | ||
| const supabase = getSupabaseClient(); | ||
| const channel = supabase.channel(`${CHANNEL_PREFIX}${targetCubid}`); | ||
|
|
||
| channel.on("broadcast", { event: EVENT_NAME }, (event) => { | ||
| const payload = event.payload as HandshakeCompletion | null; | ||
| if (!payload) return; | ||
| onComplete(payload); | ||
| }); | ||
|
|
||
| channel.subscribe(); | ||
|
|
||
| return () => { | ||
| void channel.unsubscribe(); | ||
| }; | ||
| } |
There was a problem hiding this comment.
The subscribeToHandshake function doesn't ensure the channel is subscribed before setting up event listeners, unlike notifyHandshakeComplete which uses ensureSubscribed. This could lead to race conditions where the subscription isn't ready when events are broadcasted, causing missed messages. Consider calling ensureSubscribed(channel) after line 60 and before returning the unsubscribe function, or handle the subscription status in the cleanup function.
Summary
Testing
Codex Task