diff --git a/chat.py b/chat.py
index ff32e03..c0c9777 100644
--- a/chat.py
+++ b/chat.py
@@ -223,7 +223,7 @@ CHAT_HTML = r"""
@@ -336,11 +336,23 @@ function send() {
// Local commands
const dmMatch = text.match(/^\/dm\s+@?(\S+)\s+([\s\S]+)/);
if (dmMatch) {
+ lastDmPeer = dmMatch[1];
encryptAndSendDM(dmMatch[1], dmMatch[2]);
$input.value = '';
$input.style.height = 'auto';
return;
}
+ const replyMatch = text.match(/^\/(?:reply|r)\s+([\s\S]+)/);
+ if (replyMatch) {
+ if (!lastDmPeer) {
+ addMsg({ts:Date.now()/1000, user:'***', text:'No one to reply to. Use /dm @user first.'});
+ } else {
+ encryptAndSendDM(lastDmPeer, replyMatch[1]);
+ }
+ $input.value = '';
+ $input.style.height = 'auto';
+ return;
+ }
if (text === '/users' || text === '/online') {
fetch('/keys').then(r => r.json()).then(users => {
addMsg({ts:Date.now()/1000, user:'***', text:'Users with keys: ' + users.join(', ')});
@@ -494,6 +506,7 @@ document.getElementById('pw-input').onkeydown = function(e) {
// ── E2E Encrypted DMs (ECDH + AES-256-GCM via Web Crypto) ──
let myKeyPair = null;
+let lastDmPeer = null; // for /reply
let myPubJwk = null;
const derivedKeys = {}; // cache: username -> CryptoKey (AES)
@@ -595,6 +608,8 @@ async function handleEncryptedDM(data) {
// Only decrypt if we are sender or recipient
if (data.to !== myName && data.user !== myName) return;
const otherUser = data.user === myName ? data.to : data.user;
+ // Update reply target when someone DMs us
+ if (data.user !== myName) lastDmPeer = data.user;
try {
const aesKey = await getAESKey(otherUser);
if (!aesKey) throw new Error('no key');