Dateien nach "frontend/src/tools" hochladen
This commit is contained in:
@@ -4,6 +4,7 @@ import { UserIcon, TrashIcon } from '../icons.jsx';
|
||||
import {
|
||||
getOrCreateKeyPair,
|
||||
getPublicKeyJwk,
|
||||
getFingerprint,
|
||||
deriveSharedKey,
|
||||
encryptMsg,
|
||||
decryptMsg,
|
||||
@@ -17,6 +18,7 @@ export default function Nachrichten({ toast, mobile }) {
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [sharedKey, setSharedKey] = useState(null); // null | CryptoKey | 'error'
|
||||
const [decrypted, setDecrypted] = useState({});
|
||||
const [partnerFp, setPartnerFp] = useState('');
|
||||
const [text, setText] = useState('');
|
||||
const [sending, setSending] = useState(false);
|
||||
const bottomRef = useRef(null);
|
||||
@@ -45,16 +47,22 @@ export default function Nachrichten({ toast, mobile }) {
|
||||
return () => clearInterval(pollRef.current);
|
||||
}, [activeUser?.id]);
|
||||
|
||||
// ── Shared Key ───────────────────────────────────────────────────────────────
|
||||
// ── Shared Key + Partner-Fingerprint ─────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
setSharedKey(null);
|
||||
setDecrypted({});
|
||||
setPartnerFp('');
|
||||
if (!kp || !activeUser?.public_key) return;
|
||||
try {
|
||||
const pubJwk = JSON.parse(activeUser.public_key);
|
||||
deriveSharedKey(kp.privateKey, pubJwk)
|
||||
.then(setSharedKey)
|
||||
.catch(() => setSharedKey('error'));
|
||||
// Fingerprint des Partner-Keys berechnen (aus dem auf dem Server gespeicherten Public Key)
|
||||
crypto.subtle.importKey('jwk', pubJwk, { name:'X25519' }, true, [])
|
||||
.then(k => getFingerprint({ publicKey: k }))
|
||||
.then(setPartnerFp)
|
||||
.catch(() => setPartnerFp('?'));
|
||||
} catch {
|
||||
setSharedKey('error');
|
||||
}
|
||||
@@ -241,10 +249,21 @@ export default function Nachrichten({ toast, mobile }) {
|
||||
whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>
|
||||
{activeUser.username}
|
||||
</div>
|
||||
<div style={{ color: sharedKey === 'error' ? '#ff6b9d' : 'rgba(78,205,196,0.5)',
|
||||
fontSize:8, fontFamily:'monospace', letterSpacing:1.5, marginTop:1 }}>
|
||||
{sharedKey === 'error' ? '⚠ SCHLÜSSEL INKOMPATIBEL' : '🔒 E2E VERSCHLÜSSELT · X25519 + AES-256-GCM'}
|
||||
</div>
|
||||
{sharedKey === 'error' ? (
|
||||
<div style={{ color:'#ff6b9d', fontSize:8, fontFamily:'monospace', letterSpacing:1.5, marginTop:1 }}>
|
||||
⚠ SCHLÜSSEL INKOMPATIBEL
|
||||
</div>
|
||||
) : partnerFp ? (
|
||||
<div title={`Fingerprint von ${activeUser.username} – vergleiche mit dessen Anzeige unter Einstellungen → Sicherheit`}
|
||||
style={{ color:'rgba(78,205,196,0.55)', fontSize:8, fontFamily:'monospace', letterSpacing:1, marginTop:2,
|
||||
cursor:'help', whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis' }}>
|
||||
🔒 {partnerFp}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ color:'rgba(78,205,196,0.35)', fontSize:8, fontFamily:'monospace', letterSpacing:1.5, marginTop:1 }}>
|
||||
🔒 E2E VERSCHLÜSSELT · X25519 + AES-256-GCM
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<button onClick={deleteConversation} style={{ ...S.btn('#ff6b9d', true), fontSize:10, flexShrink:0 }}>
|
||||
Verlauf löschen
|
||||
|
||||
Reference in New Issue
Block a user