대화 기록¶
메시지 원문은 백엔드에도 체인에도 없습니다. 복호화된 메시지는 XMTP 브라우저 SDK가 관리하는 로컬 MLS 데이터베이스(OPFS)에만 있습니다.
읽는 경로¶
앱은 대화를 처음 열 때 한 번 읽습니다.
XmtpMessagingAdapter.listMessages
conversation.sync() 네트워크에 쌓인 메시지를 받아 복호화해 로컬에 저장
conversation.messages() 로컬 MLS DB에서 읽는다
sync()가 먼저 필요합니다. 로컬 DB는 자동으로 최신이 아니라서, 내가 오프라인인
동안 상대가 보낸 메시지는 sync 시점에야 들어옵니다.
스트림(streamAllMessages)은 구독 이후의 메시지만 줍니다. 과거 메시지를 화면에
띄우려면 이 경로가 반드시 있어야 합니다.
읽어 온 메시지는 스트림으로 받은 것과 메시지 ID로 중복을 제거한 뒤 전송 시각으로 정렬해 합칩니다.
미해결: 새 installation은 과거를 열지 못합니다¶
MLS 키는 installation마다 다릅니다. 새 installation은 자신이 대화에 참여하기 전의 메시지를 복호화할 수 없습니다. 네트워크에 암호문이 남아 있어도 열 키가 없습니다.
그래서 다음 경우 그 브라우저의 과거 기록은 복구되지 않습니다.
- 브라우저 저장소를 비운 경우 (
Clear site data) - 다른 브라우저나 기기에서 같은 지갑으로 로그인한 경우
- installation 한도(inbox당 10개)에 걸려 기존 installation을 폐기한 경우
이는 종단간 암호화의 결과이지 버그가 아닙니다. 다만 사용자에게는 "대화가 사라졌다"로 보입니다.
후보¶
XMTP는 기기 간 기록 이전을 위한 별도 서비스를 둡니다.
HistorySyncUrls.dev = "https://message-history.dev.ephemera.network"
Client.create의 historySyncUrl 옵션과 syncAll이 이 경로를 씁니다. 기존
installation이 살아 있어야 새 installation으로 기록을 넘길 수 있습니다. 즉 저장소를
이미 비운 뒤에는 이 방법으로도 복구되지 않습니다.
검토할 때 정해야 할 것.
| 질문 | 메모 |
|---|---|
| 어디까지 보장할 것인가 | 기기 추가는 이전 가능, 저장소 삭제는 불가. 이 차이를 제품이 어떻게 설명할지 |
| 한도와의 관계 | installation 10개 한도가 있어 기기를 늘리는 데 상한이 있습니다 |
| 사용자 안내 | 저장소를 비우면 복구되지 않는다는 것을 언제 알릴지 |
원문을 백엔드에 평문으로 저장하는 방식은 검토 대상이 아닙니다. 서버가 대화를 읽을 수 있게 되기 때문입니다.
예외: 증빙된 대화의 암호문 아카이브¶
증빙에 쓴 메시지에 한해 위 한계를 우회하는 경로가 있습니다. 제안 시점에 클라이언트가 원문을 AES-256-GCM 으로 잠가 서버에 올리고, 콘텐츠 키는 XMTP 제어 메시지(E2EE)로만 참여자에게 전달합니다. 증빙에 서명한 참여자는 서명 직후 지갑 서명에서 파생한 키로 콘텐츠 키를 래핑해 서버에 맡기고, 이후 어느 기기에서든 같은 지갑 서명 한 번으로 원문을 복원할 수 있습니다.
- 서버는 암호문과 래핑된 키만 보관하고 어느 쪽도 열 수 없습니다. "서버가 대화를 읽을 수 없다"는 전제는 그대로입니다.
- 복원 자격은 실제 서명한 지갑뿐입니다. 서명하지 않은 참여자에게는 서버가 아카이브 존재 여부도 알리지 않습니다.
- 복원한 본문은 항상 content hash 를 재계산해 온체인 기록과 대조한 뒤에만 보여줍니다. 서버가 암호문을 바꿔치기하면 이 단계에서 드러납니다.
- 지갑 서명이 결정적(RFC 6979, EOA)이라는 가정에 기댑니다. ERC-1271 스마트 컨트랙트 지갑은 복원이 깨질 수 있습니다.