Files
IdP/apps/frontend/lib/e2e-chat.ts
lendry a4b4577c55 fix
2026-07-10 10:37:22 +03:00

89 lines
2.6 KiB
TypeScript

import { decryptBinary, decryptDirectMessage, encryptBinary, encryptDirectMessage } from '@/lib/e2e-crypto';
export type E2EMessageKind = 'text' | 'emoji' | 'image' | 'voice' | 'audio' | 'video' | 'video_note' | 'file' | 'location';
export interface E2EMessagePayload {
kind: E2EMessageKind;
text?: string;
emojiId?: string;
fileName?: string;
mimeType?: string;
fileSize?: number;
durationMs?: number;
latitude?: number;
longitude?: number;
address?: string;
label?: string;
}
export async function encryptE2EPayload(userId: string, peerPublicKey: string, payload: E2EMessagePayload) {
return encryptDirectMessage(userId, peerPublicKey, JSON.stringify(payload));
}
export async function decryptE2EPayload(userId: string, peerPublicKey: string, encrypted: string): Promise<E2EMessagePayload | null> {
const decrypted = await decryptDirectMessage(userId, peerPublicKey, encrypted);
if (decrypted.startsWith('🔒')) return null;
try {
return JSON.parse(decrypted) as E2EMessagePayload;
} catch {
return { kind: 'text', text: decrypted };
}
}
export async function encryptE2EBlob(userId: string, peerPublicKey: string, data: ArrayBuffer) {
return encryptBinary(userId, peerPublicKey, data);
}
export async function decryptE2EBlob(userId: string, peerPublicKey: string, encryptedBytes: ArrayBuffer) {
return decryptBinary(userId, peerPublicKey, encryptedBytes);
}
export function e2eKindFromMessageType(type: string): E2EMessageKind {
switch (type) {
case 'EMOJI':
return 'emoji';
case 'IMAGE':
return 'image';
case 'VOICE':
return 'voice';
case 'AUDIO':
return 'audio';
case 'VIDEO':
return 'video';
case 'VIDEO_NOTE':
return 'video_note';
case 'FILE':
return 'file';
case 'LOCATION':
return 'location';
default:
return 'text';
}
}
export function readableE2EPayload(payload: E2EMessagePayload | null) {
if (!payload) return '🔒 Зашифрованное сообщение';
switch (payload.kind) {
case 'emoji':
return payload.emojiId ?? '';
case 'text':
return payload.text ?? '';
case 'voice':
return 'Голосовое сообщение';
case 'audio':
return 'Аудио';
case 'image':
return 'Фото';
case 'video':
return 'Видео';
case 'video_note':
return 'Кружок';
case 'file':
return payload.fileName ?? 'Файл';
case 'location':
return payload.label?.trim() || payload.address?.trim() || payload.text?.trim() || 'Геопозиция';
default:
return '🔒 Зашифрованное сообщение';
}
}