Add multi-service Docker setup, Postgres migrations, and messaging API cleanup

This commit is contained in:
2026-01-16 00:25:22 +03:00
Unverified
parent 0b683e3c83
commit 618f55e057
22 changed files with 473 additions and 154 deletions
-16
View File
@@ -40,19 +40,9 @@ export async function decrypt(envelope: DmEnvelope, userId?: number): Promise<st
const wrappedMekB64 = envelope.wrapped_mek_b64;
if (!wrappedMekB64) throw new Error("No wrapped MEK available for decryption");
console.log("🔐 Decrypting DM envelope:", {
id: envelope.id,
senderId: envelope.senderId,
recipientId: envelope.recipientId,
hasWrappedMek: !!wrappedMekB64,
wrappedMekLength: wrappedMekB64?.length
});
// Unwrap the MEK using shared logic
const mek = await unwrapMek(wrappedMekB64, envelope, userId);
console.log("🔓 MEK unwrapped successfully, length:", mek.length);
// Decrypt the message using the unwrapped MEK
// Server encrypts with AES-GCM, so client decrypts with AES-GCM
// envelope.iv_b64 and envelope.ciphertext_b64 are base64-encoded separately
@@ -60,15 +50,9 @@ export async function decrypt(envelope: DmEnvelope, userId?: number): Promise<st
const messageNonce = ub64(envelope.iv_b64 || "");
const messageCiphertext = ub64(envelope.ciphertext_b64);
console.log("💬 Message decryption with AES-GCM:", {
ivLength: messageNonce.length,
ciphertextLength: messageCiphertext.length
});
const plaintext = await aesGcmDecrypt(messageKey, messageNonce, messageCiphertext);
const result = new TextDecoder().decode(plaintext);
console.log("✅ Decryption successful:", result);
return result;
} catch (error) {
console.error("❌ Failed to decrypt DM envelope:", error);
+3 -5
View File
@@ -319,11 +319,9 @@ export interface DMEditPayload {
id: number;
senderId: number;
recipientId: number;
iv: string;
ciphertext: string;
iv2: string;
wrappedMk: string;
salt: string;
iv_b64: string;
ciphertext_b64: string;
wrapped_mek_b64: string;
timestamp: string;
}
@@ -55,12 +55,6 @@ export class DMPanel extends MessagePanel {
}
private async parseTextPayload(env: DmEnvelope, decryptedMessages: Message[]) {
console.log("🔔 DMPanel parsing message:", {
envelopeId: env.id,
currentUserId: this.currentUser.currentUser?.id,
envelopeRecipientId: env.recipientId,
envelopeSenderId: env.senderId
});
const plaintext = await api.chats.dm.decrypt(env, this.currentUser.currentUser?.id);
const username = formatDMUsername(
env.senderId,
@@ -258,34 +252,37 @@ export class DMPanel extends MessagePanel {
}
}
if (response.type === "dmEdited" && this.dmData) {
const { id, iv, ciphertext, wrappedMk } = response.data;
try {
// Decrypt new content in-place
const plaintext = await api.chats.dm.decrypt(
{
id,
senderId: 0,
recipientId: 0,
iv_b64: iv,
ciphertext_b64: ciphertext,
wrapped_mek_b64: wrappedMk,
timestamp: new Date().toISOString()
},
this.currentUser.currentUser?.id
);
let content = plaintext;
let files: Message["files"] | undefined = undefined;
try {
const obj = JSON.parse(plaintext) as EncryptedMessageJson;
if (obj.type === "text" && obj.data) {
content = obj.data.content;
files = obj.data.files;
}
} catch {}
const updates: Partial<Message> = { content, is_edited: true, files };
this.updateMessage(id, updates);
} catch (e) {
const { id, senderId, recipientId, iv_b64, ciphertext_b64, wrapped_mek_b64, timestamp } = response.data;
if (!wrapped_mek_b64) {
this.updateMessage(id, { is_edited: true });
} else {
try {
const plaintext = await api.chats.dm.decrypt(
{
id,
senderId: senderId ?? 0,
recipientId: recipientId ?? 0,
iv_b64: iv_b64 ?? "",
ciphertext_b64: ciphertext_b64 ?? "",
wrapped_mek_b64,
timestamp: timestamp ?? new Date().toISOString()
},
this.currentUser.currentUser?.id
);
let content = plaintext;
let files: Message["files"] | undefined = undefined;
try {
const obj = JSON.parse(plaintext) as EncryptedMessageJson;
if (obj.type === "text" && obj.data) {
content = obj.data.content;
files = obj.data.files;
}
} catch {}
const updates: Partial<Message> = { content, is_edited: true, files };
this.updateMessage(id, updates);
} catch (e) {
this.updateMessage(id, { is_edited: true });
}
}
}
if (response.type === "dmDeleted" && this.dmData) {