diff --git a/server/src/index.ts b/server/src/index.ts index 16811b3..c293e14 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -139,19 +139,6 @@ function validateAvatar(avatar: unknown): string | undefined { return avatar; } -// ── Pair codes (temporary mapping: short code → groupId, 5 min TTL) ── - -import { customAlphabet } from "nanoid"; -const generatePairCode = customAlphabet("ABCDEFGHJKLMNPQRSTUVWXYZ23456789", 6); -const pairCodes = new Map(); - -setInterval(() => { - const now = Date.now(); - for (const [code, entry] of pairCodes) { - if (now > entry.expiresAt) pairCodes.delete(code); - } -}, 60_000); - // ── HTTP server (Hono) ── const honoApp = buildApp(); @@ -224,12 +211,6 @@ wss.on("connection", (ws, req) => { case "wake-peer": handleWakePeer(client, msg); break; - case "create-pair-code": - handleCreatePairCode(client, msg); - break; - case "resolve-pair-code": - handleResolvePairCode(client, msg); - break; case "leave": handleLeave(client); break; @@ -429,38 +410,6 @@ function handleSignal(client: Client, to: string, data: unknown): void { } } -function handleCreatePairCode(client: Client, msg: ClientMessage & { type: "create-pair-code" }): void { - if (typeof msg.groupId !== "string" || msg.groupId.length === 0) return; - - // Check if this groupId already has an active code - for (const [code, entry] of pairCodes) { - if (entry.groupId === msg.groupId && Date.now() < entry.expiresAt) { - send(client.ws, { type: "pair-code-created", code }); - return; - } - } - - const code = generatePairCode(); - pairCodes.set(code, { groupId: msg.groupId, expiresAt: Date.now() + 5 * 60 * 1000 }); - console.log(`[pair] created code ${code} for group ${msg.groupId.slice(0, 8)}...`); - send(client.ws, { type: "pair-code-created", code }); -} - -function handleResolvePairCode(client: Client, msg: ClientMessage & { type: "resolve-pair-code" }): void { - if (typeof msg.code !== "string" || msg.code.length !== 6) { - send(client.ws, { type: "error", code: "pair-code-not-found", message: "Code d'appairage invalide" }); - return; - } - const entry = pairCodes.get(msg.code.toUpperCase()); - if (!entry || Date.now() > entry.expiresAt) { - send(client.ws, { type: "error", code: "pair-code-not-found", message: "Code d'appairage invalide ou expiré" }); - return; - } - pairCodes.delete(msg.code.toUpperCase()); - console.log(`[pair] resolved code ${msg.code} → group ${entry.groupId.slice(0, 8)}...`); - send(client.ws, { type: "pair-code-resolved", groupId: entry.groupId }); -} - function handleLeave(client: Client): void { const lanRoom = roomManager.getRoomById(client.lanRoomId); if (!lanRoom) return; diff --git a/shared/src/protocol.ts b/shared/src/protocol.ts index b1fe6d3..3faad6d 100644 --- a/shared/src/protocol.ts +++ b/shared/src/protocol.ts @@ -40,25 +40,13 @@ export interface WakePeerMessage { deviceId: string; } -export interface CreatePairCodeMessage { - type: "create-pair-code"; - groupId: string; -} - -export interface ResolvePairCodeMessage { - type: "resolve-pair-code"; - code: string; -} - export type ClientMessage = | HelloMessage | CreatePublicRoomMessage | SignalMessage | LeaveMessage | SubscribePushMessage - | WakePeerMessage - | CreatePairCodeMessage - | ResolvePairCodeMessage; + | WakePeerMessage; // ── Server → Client messages ── @@ -105,17 +93,7 @@ export interface SignalRelayMessage { data: unknown; } -export interface PairCodeCreatedMessage { - type: "pair-code-created"; - code: string; -} - -export interface PairCodeResolvedMessage { - type: "pair-code-resolved"; - groupId: string; -} - -export type ErrorCode = "room-not-found" | "room-expired" | "rate-limit" | "pair-code-not-found"; +export type ErrorCode = "room-not-found" | "room-expired" | "rate-limit"; export interface ErrorMessage { type: "error"; @@ -129,8 +107,6 @@ export type ServerMessage = | PeerJoinedMessage | PeerLeftMessage | SignalRelayMessage - | PairCodeCreatedMessage - | PairCodeResolvedMessage | ErrorMessage; // ── Data channel messages (peer-to-peer) ── diff --git a/web/src/App.tsx b/web/src/App.tsx index bc6c7f3..a9b4254 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -2,7 +2,6 @@ import { Routes, Route } from "react-router-dom"; import Home from "./pages/Home"; import JoinRoom from "./pages/JoinRoom"; import Share from "./pages/Share"; -import Pair from "./pages/Pair"; import Settings from "./pages/Settings"; import Receive from "./pages/Receive"; import Inbox from "./pages/Inbox"; @@ -12,7 +11,6 @@ export default function App() { } /> } /> - } /> } /> } /> } /> diff --git a/web/src/components/DevicePairingPanel.tsx b/web/src/components/DevicePairingPanel.tsx deleted file mode 100644 index 4fcaffc..0000000 --- a/web/src/components/DevicePairingPanel.tsx +++ /dev/null @@ -1,187 +0,0 @@ -import { useState, useEffect } from "react"; -import { useProfileStore } from "../stores/useProfileStore"; -import { useStore } from "../stores/useStore"; - -interface DevicePairingPanelProps { - onRequestCode: (groupId: string) => void; - onResolveCode: (code: string) => void; -} - -export default function DevicePairingPanel({ - onRequestCode, - onResolveCode, -}: DevicePairingPanelProps) { - const { groupId, setGroupId } = useProfileStore(); - const pairCode = useStore((s) => s.pairCode); - const error = useStore((s) => s.error); - const [showModal, setShowModal] = useState(false); - const [mode, setMode] = useState<"show" | "enter">("show"); - const [inputCode, setInputCode] = useState(""); - const [pairError, setPairError] = useState(null); - - useEffect(() => { - if (showModal && mode === "show") { - let gid = groupId; - if (!gid) { - gid = crypto.randomUUID(); - setGroupId(gid); - } - useStore.getState().setPairCode(null); - onRequestCode(gid); - } - }, [showModal, mode]); - - useEffect(() => { - if (error && error.includes("appairage")) { - setPairError(error); - useStore.getState().setError(null); - } - }, [error]); - - const handleClose = () => { - setShowModal(false); - useStore.getState().setPairCode(null); - setPairError(null); - setInputCode(""); - }; - - const handleSubmitCode = () => { - if (inputCode.length >= 6) { - setPairError(null); - onResolveCode(inputCode); - } - }; - - const currentGroupId = useProfileStore((s) => s.groupId); - useEffect(() => { - if (mode === "enter" && showModal && currentGroupId && currentGroupId !== groupId) { - handleClose(); - } - }, [currentGroupId]); - - return ( - <> - - - {showModal && ( -
-
e.stopPropagation()} - > -
- Pair device -
-

- Link your devices -

- - {/* Tab switcher */} -
- - -
- - {mode === "show" ? ( - <> -

- Enter this code on your other device. -

- - {pairCode ? ( -

- {pairCode} -

- ) : ( -
-
-
- )} - -

- Code expires in 5 minutes. Pairing is permanent. -

- - ) : ( - <> -

- Enter the code shown on the other device. -

- - { - setInputCode(e.target.value.toUpperCase().replace(/[^A-Z0-9]/g, "")); - setPairError(null); - }} - placeholder="ABC123" - maxLength={6} - autoFocus - className="w-full px-4 py-3 bg-paper border border-paper-edge - rounded-sm text-ink text-2xl text-center font-mono tracking-[0.3em] - placeholder:text-ink-faint focus:outline-none focus:border-ink - transition-colors duration-fast ease-crisp" - onKeyDown={(e) => { - if (e.key === "Enter") handleSubmitCode(); - }} - /> - - {pairError && ( -

{pairError}

- )} - - - - )} - - -
-
- )} - - ); -} diff --git a/web/src/components/PublicRoomPanel.tsx b/web/src/components/PublicRoomPanel.tsx deleted file mode 100644 index de1dca0..0000000 --- a/web/src/components/PublicRoomPanel.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { useState } from "react"; -import { QRCodeSVG } from "qrcode.react"; -import { useStore } from "../stores/useStore"; - -interface PublicRoomPanelProps { - onCreateRoom: () => void; -} - -export default function PublicRoomPanel({ onCreateRoom }: PublicRoomPanelProps) { - const publicRoomCode = useStore((s) => s.publicRoomCode); - const publicRoomUrl = useStore((s) => s.publicRoomUrl); - const [showModal, setShowModal] = useState(false); - - const handleClick = () => { - if (publicRoomCode && publicRoomUrl) { - setShowModal(true); - } else { - onCreateRoom(); - setShowModal(true); - } - }; - - return ( - <> - - - {showModal && ( - setShowModal(false)} - /> - )} - - ); -} - -function PublicRoomModal({ - code, - url, - onClose, -}: { - code: string | null; - url: string | null; - onClose: () => void; -}) { - const [copied, setCopied] = useState(false); - - const copyToClipboard = () => { - if (!url) return; - navigator.clipboard.writeText(url); - setCopied(true); - setTimeout(() => setCopied(false), 1500); - }; - - return ( -
-
e.stopPropagation()} - > -
- Public link -
-

- Receive from anyone -

- - {!code || !url ? ( -

Generating…

- ) : ( - <> -
-
- -
-
- -
-

- {code.toUpperCase()} -

- -
- -

- Anyone with this code or link can send you files. Expires in 10 minutes. -

- - )} - - -
-
- ); -} diff --git a/web/src/hooks/useSignaling.ts b/web/src/hooks/useSignaling.ts index 8d3f21d..4f08ce5 100644 --- a/web/src/hooks/useSignaling.ts +++ b/web/src/hooks/useSignaling.ts @@ -240,18 +240,6 @@ export function useSignaling(joinCode?: string) { case "public-room-created": setPublicRoom(msg.code, msg.url, msg.expiresAt); break; - case "pair-code-created": - useStore.getState().setPairCode(msg.code); - break; - case "pair-code-resolved": { - // Store the groupId and reconnect to join the group room - useProfileStore.getState().setGroupId(msg.groupId); - // Update the signaling client's profile so reconnect sends the new groupId - signalingRef.current?.updateProfile({ groupId: msg.groupId }); - signalingRef.current?.disconnect(); - setTimeout(() => signalingRef.current?.connect(), 500); - break; - } case "error": setError(msg.message); break; @@ -556,14 +544,6 @@ export function useSignaling(joinCode?: string) { signalingRef.current?.send({ type: "wake-peer", deviceId }); }, []); - const requestPairCode = useCallback((groupId: string) => { - signalingRef.current?.send({ type: "create-pair-code", groupId }); - }, []); - - const resolvePairCode = useCallback((code: string) => { - signalingRef.current?.send({ type: "resolve-pair-code", code: code.toUpperCase() }); - }, []); - return { sendFiles, sendText, @@ -571,7 +551,5 @@ export function useSignaling(joinCode?: string) { rejectTransfer, createPublicRoom, wakePeer, - requestPairCode, - resolvePairCode, }; } diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index 88d5f06..eeeceb3 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -145,16 +145,11 @@ function HomeConnected() {
-