diff --git a/frontend/src/components/MeshChat/index.tsx b/frontend/src/components/MeshChat/index.tsx
index 515e0f5..bf13cee 100644
--- a/frontend/src/components/MeshChat/index.tsx
+++ b/frontend/src/components/MeshChat/index.tsx
@@ -1492,778 +1492,7 @@ const MeshChat = React.memo(function MeshChat(props: MeshChatProps) {
>
)}
- {/* Dead Drop chat UI moved to Infonet Terminal → Messages */}
- {false && !dashboardRestrictedTab && activeTab === 'dms' && (
- <>
- {/* Sub-nav: Contacts | Inbox | Muted | (back to contacts from chat) */}
-
- {dmView === 'chat' ? (
- <>
- {
- setDmView('contacts');
- setSelectedContact('');
- setDmMessages([]);
- }}
- className="text-[13px] font-mono text-[var(--text-muted)] hover:text-cyan-400 transition-colors"
- >
- < BACK
-
-
- {selectedContact.slice(0, 16)}
-
- {(() => {
- const c = contacts[selectedContact];
- if (!c) return null;
- const trust = getContactTrustSummary(c);
- if (trust?.transparencyConflict) {
- return (
-
- HISTORY CONFLICT
-
- );
- }
- if (trust?.state === 'continuity_broken') {
- return (
-
- CONTINUITY BROKEN
-
- );
- }
- if (trust?.state === 'mismatch') {
- return (
-
- PREKEY CHANGED
-
- );
- }
- if (trust?.registryMismatch) {
- return (
-
- KEY MISMATCH
-
- );
- }
- if (trust?.state === 'sas_verified') {
- return (
-
- SAS VERIFIED
-
- );
- }
- if (trust?.state === 'invite_pinned') {
- return (
-
- INVITE PINNED
-
- );
- }
- if (trust?.state === 'tofu_pinned') {
- return (
-
- TOFU ONLY
-
- );
- }
- return null;
- })()}
- {(() => {
- const c = contacts[selectedContact];
- if (!c) return null;
- if (c.witness_count && c.witness_count > 0) {
- return (
-
- WITNESSED {c.witness_count}
-
- );
- }
- return null;
- })()}
- {(() => {
- const c = contacts[selectedContact];
- if (!c) return null;
- if (c.vouch_count && c.vouch_count > 0) {
- return (
-
- VOUCHES {c.vouch_count}
-
- );
- }
- return null;
- })()}
-
- {dmTrustPrimaryButtonLabel}
-
- handleVouch(selectedContact)}
- className="ml-2 text-[12px] font-mono px-2 py-0.5 border border-purple-800/40 text-purple-400/90 hover:text-purple-300 hover:border-purple-600/60 transition-colors"
- >
- VOUCH
-
- void handleRefreshSelectedContact()}
- disabled={dmMaintenanceBusy}
- className="ml-2 text-[12px] font-mono px-2 py-0.5 border border-amber-800/40 text-amber-300/90 hover:text-amber-200 hover:border-amber-600/60 transition-colors disabled:opacity-40"
- >
- REFRESH
-
- void handleResetSelectedContact()}
- disabled={dmMaintenanceBusy}
- className="ml-2 text-[12px] font-mono px-2 py-0.5 border border-red-800/40 text-red-300/90 hover:text-red-200 hover:border-red-600/60 transition-colors disabled:opacity-40"
- >
- RESET
-
- >
- ) : (
- <>
- setDmView('contacts')}
- className={`text-[13px] font-mono px-2 py-0.5 transition-colors ${
- dmView === 'contacts'
- ? 'text-cyan-400 bg-cyan-950/30'
- : 'text-[var(--text-muted)] hover:text-gray-400'
- }`}
- >
- CONTACTS
-
- setDmView('inbox')}
- className={`text-[13px] font-mono px-2 py-0.5 transition-colors flex items-center gap-1 ${
- dmView === 'inbox'
- ? 'text-cyan-400 bg-cyan-950/30'
- : 'text-[var(--text-muted)] hover:text-gray-400'
- }`}
- >
- INBOX
- {accessRequests.length > 0 && (
-
- )}
-
- setDmView('muted')}
- className={`text-[13px] font-mono px-2 py-0.5 transition-colors flex items-center gap-1 ${
- dmView === 'muted'
- ? 'text-cyan-400 bg-cyan-950/30'
- : 'text-[var(--text-muted)] hover:text-gray-400'
- }`}
- >
-
- MUTED
- {mutedArray.length > 0 && (
-
- ({mutedArray.length})
-
- )}
-
- setShowAddContact(!showAddContact)}
- disabled={secureDmBlocked}
- className="ml-auto p-1 hover:bg-[var(--hover-accent)] text-[var(--text-muted)] hover:text-cyan-400 transition-colors"
- title="Request access"
- >
-
-
- >
- )}
-
- {dmView === 'chat' && showSas && sasPhrase && (
-
- SAS:
{sasPhrase}
- {selectedContactInfo &&
- selectedContactTrustSummary?.state === 'invite_pinned' && (
-
- This contact was anchored by an imported signed invite. SAS is still useful
- as an extra continuity check.
-
- )}
- {selectedContactInfo &&
- selectedContactTrustSummary?.state === 'tofu_pinned' && (
-
- First contact is still TOFU-only. Compare this phrase out of band before
- treating the sender as verified.
-
- )}
- {selectedContactInfo &&
- selectedContactTrustSummary?.state !== 'sas_verified' &&
- selectedContactTrustSummary?.state !== 'mismatch' &&
- selectedContactTrustSummary?.state !== 'continuity_broken' &&
- !selectedContactTrustSummary?.transparencyConflict && (
-
- setSasConfirmInput(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === 'Enter') {
- e.preventDefault();
- void handleConfirmSelectedContactSas();
- }
- }}
- placeholder="Type the phrase you both confirmed"
- className="flex-1 min-w-0 bg-black/30 border border-cyan-900/30 px-2 py-1 text-[12px] font-mono text-cyan-100 placeholder:text-cyan-700/70 focus:outline-none focus:border-cyan-600/60"
- />
- void handleConfirmSelectedContactSas()}
- disabled={dmMaintenanceBusy}
- className="text-[12px] font-mono px-2 py-1 border border-emerald-800/40 text-emerald-300 hover:text-emerald-200 hover:border-emerald-600/60 transition-colors disabled:opacity-40"
- >
- CONFIRM SAS
-
-
- )}
- {selectedContactInfo &&
- selectedContactTrustSummary?.state === 'continuity_broken' &&
- selectedContactTrustSummary?.rootMismatch && (
- <>
-
- {`${rootWitnessContinuityLabel(selectedContactTrustSummary)} changed for this contact.`}{' '}
- Compare the SAS phrase for the newly observed root, then recover only if
- the ceremony checks out.
-
-
- setSasConfirmInput(e.target.value)}
- onKeyDown={(e) => {
- if (e.key === 'Enter') {
- e.preventDefault();
- void handleRecoverSelectedContactRootContinuity();
- }
- }}
- placeholder="Type the phrase you both confirmed for the new root"
- className="flex-1 min-w-0 bg-black/30 border border-red-900/30 px-2 py-1 text-[12px] font-mono text-cyan-100 placeholder:text-red-700/70 focus:outline-none focus:border-red-600/60"
- />
- void handleRecoverSelectedContactRootContinuity()}
- disabled={dmMaintenanceBusy}
- className="text-[12px] font-mono px-2 py-1 border border-red-800/40 text-red-300 hover:text-red-200 hover:border-red-600/60 transition-colors disabled:opacity-40"
- >
- RECOVER ROOT
-
-
- >
- )}
- {selectedContactInfo?.remotePrekeyMismatch && (
-
- {selectedContactTrustSummary?.rootMismatch
- ? `${rootWitnessContinuityLabel(selectedContactTrustSummary)} changed. Recover only after you compare the new SAS phrase out of band.`
- : 'Acknowledge the changed fingerprint first, then compare and confirm SAS again.'}
-
- )}
-
- )}
-
- {activeTab === 'dms' && !secureDmBlocked && (
-
-
- {dmTransportStatus.label}
-
-
- {dmTransportMode === 'reticulum'
- ? 'Direct private delivery active.'
- : dmTransportMode === 'hidden'
- ? 'Hidden transport active.'
- : dmTransportMode === 'relay'
- ? 'Relay fallback active.'
- : dmTransportMode === 'ready'
- ? 'Private lane ready.'
- : 'Lower-trust mode.'}
-
-
- )}
-
- {activeTab === 'dms' && unresolvedSenderSealCount > 0 && (
-
-
- UNRESOLVED SEALED SENDERS
-
-
- {unresolvedSenderSealCount} sealed-sender message
- {unresolvedSenderSealCount === 1 ? '' : 's'} could not be mapped to a
- trusted contact or verified sender key. Keep Wormhole reachable and refresh
- contact trust before relying on them.
-
-
- )}
-
- {activeTab === 'dms' && dmView === 'chat' && dmTrustHint && selectedContactInfo && (
-
-
-
-
- {dmTrustHint.title}
-
-
{dmTrustHint.detail}
- {selectedContactInfo.remotePrekeyMismatch && (
-
- pinned {shortTrustFingerprint(selectedContactInfo.remotePrekeyFingerprint)} • observed{' '}
- {shortTrustFingerprint(selectedContactInfo.remotePrekeyObservedFingerprint)}
-
- )}
- {!selectedContactInfo.remotePrekeyMismatch &&
- selectedContactInfo.remotePrekeyRootMismatch && (
-
- pinned root {shortTrustFingerprint(selectedContactInfo.remotePrekeyRootFingerprint)} •
- observed root{' '}
- {shortTrustFingerprint(selectedContactInfo.remotePrekeyObservedRootFingerprint)}
-
- )}
- {!selectedContactInfo.remotePrekeyMismatch &&
- selectedContactTrustSummary?.state === 'tofu_pinned' &&
- selectedContactInfo.remotePrekeyFingerprint && (
-
- first-sight pin {shortTrustFingerprint(selectedContactInfo.remotePrekeyFingerprint)} •
- verify before sensitive use
-
- )}
- {!selectedContactInfo.remotePrekeyMismatch &&
- selectedContactTrustSummary?.state === 'invite_pinned' &&
- (selectedContactInfo.invitePinnedTrustFingerprint ||
- selectedContactInfo.remotePrekeyFingerprint) && (
-
- invite pin{' '}
- {shortTrustFingerprint(
- selectedContactInfo.invitePinnedTrustFingerprint ||
- selectedContactInfo.remotePrekeyFingerprint,
- )}{' '}
- •
- {selectedContactTrustSummary?.rootAttested &&
- (selectedContactInfo.invitePinnedRootFingerprint ||
- selectedContactInfo.remotePrekeyRootFingerprint)
- ? ` ${rootWitnessBadgeLabel(selectedContactTrustSummary).toLowerCase()} ${shortTrustFingerprint(
- selectedContactInfo.invitePinnedRootFingerprint ||
- selectedContactInfo.remotePrekeyRootFingerprint,
- )} •`
- : ''}{' '}
- imported out of band before first contact
-
- )}
- {selectedContactTrustSummary?.state === 'continuity_broken' &&
- selectedContactTrustSummary?.rootMismatch && (
-
- {`${rootWitnessContinuityLabel(selectedContactTrustSummary).toLowerCase()} broke for this contact.`}{' '}
- Re-verify SAS or replace the signed invite before trusting the new
- root.
-
- )}
- {selectedContactInfo.remotePrekeyTransparencyConflict && (
-
- prekey history conflict observed and trust stays degraded until you
- explicitly acknowledge the changed fingerprint.
-
- )}
- {selectedContactInfo.remotePrekeyLookupMode === 'legacy_agent_id' && (
-
- bootstrap path: legacy direct agent ID lookup.
- {selectedContactInfo.invitePinnedPrekeyLookupHandle
- ? ' Refresh from the signed invite to tighten lookup privacy.'
- : ' Import or re-import a signed invite to avoid stable-ID lookup.'}
-
- )}
- {selectedContactInfo.remotePrekeyLookupMode === 'invite_lookup_handle' && (
-
- bootstrap path: invite-scoped lookup handle. Stable agent ID was not
- required on the lookup path.
-
- )}
- {(selectedContactInfo.witness_count ?? 0) > 0 && (
-
- witness observations: {selectedContactInfo.witness_count}
- {selectedContactInfo.witness_checked_at
- ? `, last seen ${timeAgo(
- selectedContactInfo.witness_checked_at > 1_000_000_000_000
- ? selectedContactInfo.witness_checked_at
- : selectedContactInfo.witness_checked_at * 1000,
- )}`
- : ''}
-
- )}
-
-
-
- {dmTrustPrimaryButtonLabel}
-
- {selectedContactInfo.remotePrekeyMismatch &&
- !selectedContactTrustSummary?.rootMismatch && (
- void handleTrustSelectedRemotePrekey()}
- disabled={dmMaintenanceBusy}
- className="text-[12px] font-mono px-2 py-0.5 border border-orange-700/40 text-orange-300 hover:text-orange-200 hover:border-orange-500/60 transition-colors disabled:opacity-40"
- >
- TRUST NEW KEY
-
- )}
-
-
-
- )}
-
- {/* Add contact / request access form */}
-
- {showAddContact && dmView !== 'chat' && !secureDmBlocked && (
-
-
-
- Enter an Agent ID for a contact you already pinned with a signed invite
- to request Dead Drop access. If you only have older local state, use
- terminal dm add only for
- legacy migration.
-
-
- setAddContactId(e.target.value)}
- placeholder="!sb_a3f2c891..."
- className="flex-1 bg-[var(--bg-secondary)]/50 border border-[var(--border-primary)] text-sm font-mono text-cyan-300 px-2 py-1 outline-none placeholder:text-[var(--text-muted)]"
- onKeyDown={(e) => {
- if (e.key === 'Enter') {
- handleRequestComposerAction();
- }
- }}
- />
-
- REQUEST
-
-
- {pendingSent.includes(addContactId.trim()) && (
-
- Request already sent
-
- )}
-
-
- )}
-
-
- {/* Content area */}
-
- {secureDmBlocked && (
-
-
-
-
-
-
- DEAD DROP LOCKED
-
-
- Need Wormhole activated.
-
-
- Contacts, inbox, and private messages unlock once the private lane is up.
-
-
-
- )}
-
- {/* CONTACTS VIEW */}
- {!secureDmBlocked && dmView === 'contacts' && (
- <>
- {contactList.length === 0 && (
-
- No contacts yet. Use + to
- request access.
-
- )}
- {contactList.map(([id, c]) => {
- const trust = getContactTrustSummary(c);
- return (
-
openChat(id)}
- >
-
-
- {c.alias || id.slice(0, 16)}
-
- {c.remotePrekeyMismatch && (
-
- REVERIFY
-
- )}
- {!c.remotePrekeyMismatch && c.verify_mismatch && (
-
- MISMATCH
-
- )}
- {!c.remotePrekeyMismatch && !c.verify_mismatch && trust?.state === 'invite_pinned' && (
-
- INVITE PINNED
-
- )}
- {!c.remotePrekeyMismatch && !c.verify_mismatch && trust?.state === 'sas_verified' && (
-
- SAS VERIFIED
-
- )}
- {!c.remotePrekeyMismatch &&
- !c.verify_mismatch &&
- !c.remotePrekeyTransparencyConflict &&
- c.remotePrekeyLookupMode === 'legacy_agent_id' && (
-
- LEGACY LOOKUP
-
- )}
- {!c.remotePrekeyMismatch && !c.verify_mismatch && c.remotePrekeyTransparencyConflict && (
-
- HISTORY CONFLICT
-
- )}
- {!c.remotePrekeyMismatch &&
- !c.verify_mismatch &&
- trust?.state === 'tofu_pinned' && (
-
- TOFU ONLY
-
- )}
- {
- e.stopPropagation();
- handleBlockDM(id);
- }}
- className="ml-auto p-0.5 text-[var(--text-muted)] hover:text-red-400 hover:bg-red-900/20 transition-colors"
- title="Block"
- >
-
-
-
- );
- })}
- {pendingSent.length > 0 && (
- <>
-
- PENDING SENT
-
- {pendingSent.map((id) => (
-
-
- {id.slice(0, 16)}
-
- awaiting
-
-
- ))}
- >
- )}
- >
- )}
-
- {/* INBOX VIEW — access requests */}
- {!secureDmBlocked && dmView === 'inbox' && (
- <>
- {accessRequests.length === 0 && (
-
- No incoming requests
-
- )}
- {accessRequests.map((req) => {
- const requestActionsAllowed = shouldAllowRequestActions(req);
- const recoveryState = req.sender_recovery_state;
- return (
-
-
-
-
- {req.sender_id.slice(0, 16)}
-
- {recoveryState === 'verified' && (
-
- VERIFIED
-
- )}
- {recoveryState === 'pending' && (
-
- RECOVERY PENDING
-
- )}
- {recoveryState === 'failed' && (
-
- RECOVERY FAILED
-
- )}
-
- {timeAgo(req.timestamp)}
-
-
-
- Requesting Dead Drop access
-
- {req.geo_hint && (
-
- Geo hint (not proof): {req.geo_hint}
-
- )}
- {!requestActionsAllowed && (
-
- Sender authority is not verified yet. Actions stay disabled until
- local recovery succeeds.
-
- )}
-
- handleAcceptRequest(req.sender_id)}
- disabled={!requestActionsAllowed}
- className={`flex items-center gap-1 text-[13px] font-mono px-2 py-0.5 transition-colors ${
- requestActionsAllowed
- ? 'bg-cyan-900/20 text-cyan-400 hover:bg-cyan-800/30'
- : 'bg-cyan-950/10 text-cyan-700 cursor-not-allowed opacity-50'
- }`}
- >
- ACCEPT
-
- handleDenyRequest(req.sender_id)}
- disabled={!requestActionsAllowed}
- className={`flex items-center gap-1 text-[13px] font-mono px-2 py-0.5 transition-colors ${
- requestActionsAllowed
- ? 'bg-gray-900/30 text-gray-400 hover:bg-gray-800/40'
- : 'bg-gray-950/20 text-gray-600 cursor-not-allowed opacity-50'
- }`}
- >
- DENY
-
- handleBlockDM(req.sender_id)}
- disabled={!requestActionsAllowed}
- className={`flex items-center gap-1 text-[13px] font-mono px-2 py-0.5 ml-auto transition-colors ${
- requestActionsAllowed
- ? 'text-[var(--text-muted)] hover:text-red-400 hover:bg-red-900/20'
- : 'text-[var(--text-muted)] opacity-50 cursor-not-allowed'
- }`}
- >
- BLOCK
-
-
-
- );
- })}
- >
- )}
-
- {/* MUTED LIST VIEW */}
- {!secureDmBlocked && dmView === 'muted' && (
- <>
- {mutedArray.length === 0 && (
-
- No muted users
-
- )}
- {mutedArray.map((uid) => (
-
-
-
- {uid.slice(0, 20)}
-
- handleUnmute(uid)}
- className="flex items-center gap-1 text-[12px] font-mono px-2 py-0.5 bg-cyan-900/20 text-cyan-500 hover:bg-cyan-800/30 transition-colors"
- >
- UNMUTE
-
-
- ))}
- >
- )}
-
- {/* CHAT VIEW */}
- {!secureDmBlocked && dmView === 'chat' && (
- <>
- {dmMessages.length === 0 && (
-
-
- E2E encrypted dead drop — no messages yet
-
- )}
- {dmMessages.map((m) => (
-
-
-
- {m.sender_id === identity?.nodeId
- ? 'you'
- : m.sender_id.slice(0, 12)}
-
- {m.sender_id !== identity?.nodeId && m.seal_verified === true && (
-
- VERIFIED
-
- )}
- {m.sender_id !== identity?.nodeId && m.seal_resolution_failed && (
-
- SEAL UNRESOLVED
-
- )}
- {m.sender_id !== identity?.nodeId &&
- !m.seal_resolution_failed &&
- m.seal_verified === false && (
-
- UNVERIFIED
-
- )}
- {m.transport && (
-
- {m.transport === 'reticulum' ? 'DIRECT' : 'RELAY'}
-
- )}
-
- {m.plaintext || '[encrypted]'}
-
-
- {timeAgo(m.timestamp)}
-
-
-
- ))}
- >
- )}
-
-
- >
- )}
+ {/* Dead Drop chat UI: Infonet Terminal → Messages */}
{/* INPUT BAR */}
@@ -2341,21 +1570,15 @@ const MeshChat = React.memo(function MeshChat(props: MeshChatProps) {
? privateInfonetReady
? `→ INFONET${selectedGate ? ` / ${selectedGate}` : ''}${privateInfonetTransportReady ? '' : ' / EXPERIMENTAL ENCRYPTION'}`
: '→ PRIVATE LANE LOCKED'
- : activeTab === 'meshtastic'
- ? canUsePublicMeshInput
- ? meshDirectTarget
- ? `→ MESH / TO ${meshDirectTarget.toUpperCase()} / FROM ${activePublicMeshAddress.toUpperCase()}`
- : `→ MESH / ${meshRegion} / ${meshChannel} / ${activePublicMeshAddress.toUpperCase()}`
- : publicMeshBlockedByWormhole
- ? '→ MESH BLOCKED / WORMHOLE ACTIVE'
+ : canUsePublicMeshInput
+ ? meshDirectTarget
+ ? `→ MESH / TO ${meshDirectTarget.toUpperCase()} / FROM ${activePublicMeshAddress.toUpperCase()}`
+ : `→ MESH / ${meshRegion} / ${meshChannel} / ${activePublicMeshAddress.toUpperCase()}`
+ : publicMeshBlockedByWormhole
+ ? '→ MESH BLOCKED / WORMHOLE ACTIVE'
: hasStoredPublicLaneIdentity
? '→ MESH OFF'
- : '→ MESH LOCKED'
- : activeTab === 'dms' && secureDmBlocked
- ? '→ DEAD DROP LOCKED'
- : dmView === 'chat' && selectedContact
- ? `→ DEAD DROP / ${selectedContact.slice(0, 14)}`
- : '→ SELECT TARGET'}
+ : '→ MESH LOCKED'}
)}
@@ -2386,19 +1609,6 @@ const MeshChat = React.memo(function MeshChat(props: MeshChatProps) {
OPEN PRIVATE LANE BRIEF
- ) : activeTab === 'dms' && secureDmBlocked ? (
- setDeadDropUnlockOpen(true)}
- className="w-full flex items-center justify-between gap-2 px-3 py-2 border border-cyan-700/40 bg-cyan-950/15 text-cyan-300 hover:bg-cyan-950/25 hover:border-cyan-500/50 transition-colors"
- >
-
-
- UNLOCK DEAD DROP
-
-
- NEED WORMHOLE
-
-
) : activeTab === 'meshtastic' && !canUsePublicMeshInput ? (