Skip to main content
Chat XDK는 X Chat을 위한 키 관리, 암호화, 복호화 및 서명을 처리합니다. X HTTP API를 호출하지 않습니다Python 또는 TypeScript XDK와 함께 사용하거나, HTTPS와 사용자 액세스 토큰과 함께 사용하세요. 앱 안내: 시작하기. 샘플 봇: chat-xdk/examples.

설치

PyPI 패키지는 chatxdk이며, chat_xdk로 임포트합니다. Python 3.10+ 필요.

빠른 시작

키를 로드하고, 신원을 한 번 설정하고, 백로그를 복호화하고, 라이브 이벤트 하나를 복호화한 후, 메시지를 암호화합니다. 시작하기에서와 같이 전송 본문을 POST /2/chat/conversations/{id}/messages에 연결하세요. 스니펫은 선택적 세션 저장소 두 개를 사용하여 가장 짧은 호출 형식을 취합니다: set_signing_keys는 다른 참가자의 공개 키(공개 키 엔드포인트에서 가져옴)를 보관하여 복호화 호출이 호출별 인수 없이 발신자를 검증할 수 있게 하고, set_cache_keys(true)는 SDK가 각 대화의 검증된 키를 기억하도록 하여 암호화 호출에 대화 ID와 텍스트만 필요하도록 합니다. 둘 중 하나를 건너뛰고 호출마다 동일한 값을 전달할 수도 있습니다—두 방식 모두 동일하게 검증합니다. 복호화를 참고하세요.

라이프사이클과 키

SDK를 구성하고, 개인 키를 저장하고(패스코드로 보호되는 보안 키 백업 또는 로컬 키 blob), Chat API에 공개 키를 등록한 다음, unlock이나 import 이후에 **set_identity(user_id, signing_key_version)**를 호출하세요—이는 모든 서명 작업이 기본적으로 사용할 발신자와 서명 키 버전을 설정하므로, encrypt 및 prepare 메서드가 호출별 신원 인수 없이도 동작합니다. generate_keypairs는 기기/앱 신원당 한 번 호출하세요. 등록 페이로드를 공개 키 엔드포인트에 게시하세요. 모든 바인딩에서 보안 키 백업에는 setup / unlock(및 관련 패스코드 헬퍼)을 사용하세요. export_keys / import_keys(봇과 서버를 위한 원시 키 blob 영속화)는 네이티브 바인딩에서만 사용 가능합니다—Python, Go, .NET, JVM, Rust. JS/WASM 바인딩은 원시 키 내보내기 또는 가져오기를 노출하지 않습니다: 브라우저에서 인스턴스에 접근할 수 있는 스크립트라면 무엇이든 신원을 유출할 수 있기 때문에, JS는 키를 보안 키 백업 안에 보관합니다. 요청당 백업 realm 왕복을 피하려는 JS 서버는 요청 간에 잠금 해제된 Chat 인스턴스 하나를 재사용하거나, 키 blob이 지원되는 네이티브 바인딩을 실행해야 합니다. SDK는 또한 등록된 공개 키에 대해 X API가 보고하는 버전이 필요합니다. 그래야 다른 버전을 대상으로 하는 키 변경 항목이 건너뛰어집니다. set_identity는 이를 사용자 ID와 함께 기록합니다. import_keys는 이를 선택적 인수로 직접 받습니다(Rust와 Go는 import_keys_with_version / ImportKeysWithVersion을 사용).
보안 키 백업 구성은 세 가지 형태를 허용합니다: X API juicebox_config 객체(권장—그대로 전달), 전체 sdk_config 래퍼, 또는 순수 token_map. 선택 사항: 서명 검증은 기본적으로 켜져 있습니다(reject_unverified = true). 이를 비활성화하려면 set_reject_unverified(false)를 호출하세요(권장하지 않음). 백업 realm 구성이 변경되면 update_config; UI 상태를 위해 is_unlocked / has_identity_key. 전체 필드 목록은 chat-xdk 저장소 스텁에서 확인할 수 있습니다.

대화 키

세 개의 prepare 메서드는 각각 한 번의 호출로 키 변경에 필요한 모든 작업을 수행합니다: 새 대화 키를 생성하고, 각 참가자에 대해 암호화하며(전달한 공개 키로), 변경 사항을 서명합니다. 발신자 신원과 서명 키 버전은 세션(set_identity)에서 가져옵니다. 재정의하려면 params에 sender_id / signing_key_version을 설정하세요. 모두 동일한 PreparedConversationChange 형태를 반환하며 POST할 준비가 되어 있습니다—conversation_participant_keys에서 SDK 필드 encrypted_key를 **encrypted_conversation_key**로 이름을 바꾸고, 액션 서명을 필수 action_signatures 본문 필드로 매핑하세요. encrypt_message 및 미디어에 사용할 원시 키 바이트를 보관하세요. API의 암호화된 봉투를 encrypt에 전달하지 마세요.
래핑하기 전에 가져온 키를 검증하세요. prepare 메서드는 전달된 공개 키로 새 대화 키를 암호화합니다. 전달하기 전에 각 가져온 레코드에 대해 verify_key_binding(identity, signing, signature)를 호출하세요—공개 키 API의 public_key, signing_public_key, identity_public_key_signature 필드를 전달하면 대체된 신원 키가 대화 키를 받는 것을 방지할 수 있습니다.
키 변경 이벤트 페이로드에 extract_conversation_keys를 사용하여 { keys, latest_version }을 재구성하세요. decrypt_conversation_key는 단일 ECIES blob을 언랩합니다.
그룹 생성 및 멤버 추가의 경우, 각 메서드에 필요한 params를 전달하세요(prepare_group_create의 경우 멤버/관리자 ID 목록; prepare_group_members_change의 경우 새 멤버와 현재 명단)—샘플은 그룹을 참고하세요. 둘 다 두 개의 액션 서명을 반환하며, POST에는 둘 다 포함해야 합니다.

복호화

**decrypt_events**는 이력 및 백로그용입니다: 스트림에서 대화 키를 추출하고, 복호화된 메시지를 반환하며, 전체 배치를 실패시키는 대신 이벤트별 오류를 수집합니다. **decrypt_event**는 단일 라이브 이벤트용입니다. 실패 시 예외를 발생/던집니다. SDK가 발신자를 검증할 수 있도록 서명 키를 전달하세요. API 공개 키 필드를 SigningKeyEntry로 매핑하세요: public_key_versionpublic_key_version(동일한 이름), signing_public_keypublic_key, public_keyidentity_public_key, 그리고 identity_public_key_signatureuser_id. 두 개의 선택적 세션 저장소를 사용하면 호출별 키 인수를 생략할 수 있습니다:
  • **set_signing_keys(entries)**는 참가자의 서명 키를 저장합니다. 서명 키 인수를 생략하거나 빈 값을 전달하는 복호화 호출은 저장소를 대신 사용합니다. 검증 자체는 동일합니다—키는 이 호출을 통해서만 저장소에 진입하며, 복호화 대상 이벤트에서는 절대 들어오지 않습니다. 각 호출은 이전 세트를 대체합니다.
  • **set_cache_keys(true)**는 대화 키 캐시를 활성화합니다(기본값 꺼짐). 활성화된 동안 decrypt_events는 대화별로, 키 변경이 유효한 서명을 담고 있던 최신 키를 캐시합니다. decrypt_event는 대화 키 인수가 생략되었을 때 여기에 폴백하고, encrypt 헬퍼는 생략된 대화 키를 여기에서 해석합니다. 비활성화하면 캐시가 지워집니다.
명시적으로 비어 있지 않은 인수는 항상 저장소보다 우선합니다. 명시적인 호출별 인수는 여전히 일급이며—서버리스 또는 다중 인스턴스 배포에서는 요청이 저장소가 비어 있는 새 인스턴스에 도착할 수 있으므로 올바른 선택입니다. 검증은 기본적으로 필수입니다: 서명 키를 생략해도 검증이 건너뛰어지지 않습니다. 아무것도 전달하지 않고 아무것도 저장되어 있지 않으면 서명된 이벤트는 실패합니다(decrypt_events의 경우 errors에 수집되고, decrypt_event의 경우 던져짐). 실제로 검증을 건너뛰려면 먼저 set_reject_unverified(false)를 호출해야 합니다(프로덕션에서는 권장하지 않음).

암호화 및 전송 헬퍼

**encrypt_message(conversation_id, text)**는 텍스트 메시지에 대한 서명된 암호문을 생성합니다. 선택적으로 entities, attachments(media_hash_key를 통해), should_notify, ttl_msec을 사용할 수 있습니다. 발신자 신원은 세션(set_identity)에서, 대화 키는 선택적 키 캐시(set_cache_keys)에서 가져옵니다—또는 sender_id / signing_key_versionconversation_key + conversation_key_version을 명시적으로 전달하세요. SDK가 message_id(서명된 이벤트에 삽입되는 UUID)를 생성하여 페이로드에 반환합니다—직접 만들지 마세요. 재시도 시 동일한 페이로드를 재사용하여 ID가 두 번 생성되지 않도록 하세요. 페이로드를 send-message 본문에 매핑하세요: message_idmessage_id, encrypted_contentencoded_message_create_event, encoded_event_signatureencoded_message_event_signature. 답장은 이벤트 기반입니다. encrypt_reply(conversation_id, text, reply_to_event)는 답장 대상이 되는 base64 원시 이벤트를 받습니다. SDK는 이로부터 인용된 미리보기(시퀀스 ID, 발신자, 텍스트, 엔티티, 첨부 파일)를 유도하고, 서명된 원본을 발신 메시지에 삽입하여 수신자가 인용을 검증할 수 있도록 합니다. 원본이 답장보다 이전 키 버전으로 암호화된 경우 reply_to_ckces—원시 키 변경 이벤트—를 전달하세요. 원본이 편집된 경우, 원시 편집 이벤트를 reply_to_edit_event로 전달하세요: 그러면 미리보기는 메시지가 현재 말하는 내용을 인용하고(텍스트와 엔티티는 편집본에서 가져옴), 편집본이 원본과 함께 전달되어 수신자가 확인할 수 있습니다. 명시적인 reply_to_* 필드는 원시 이벤트를 더 이상 보유하지 않은 호출자를 위한 재정의로 남아 있습니다. 반응 또한 이벤트 기반입니다. encrypt_add_reaction(target_event, emoji)encrypt_remove_reaction(...)은 반응 대상이 되는 원시 이벤트에서 대화 ID와 대상 시퀀스 ID를 유도합니다. 동일한 params로 반응을 추가하고 나중에 제거할 수 있습니다. 원시 이벤트를 더 이상 보유하지 않은 경우에만 conversation_idtarget_message_sequence_id를 명시적으로 설정하세요. 수신 측에서는, 답장을 인용하는 복호화된 메시지가 reply_preview_validation("Valid" / "Invalid"; JS 바인딩은 'valid' / 'invalid' 사용)을 담고 있습니다: SDK는 삽입된 원본의 서명을 서명 키로 검증하고—이벤트에 담긴 키로는 절대 검증하지 않음—복호화한 뒤, 인용된 내용과 작성자를 원본과 비교했습니다. 미리보기에 편집 이벤트가 삽입되어 있으면 SDK는 동일한 방식으로 편집본을 검증하고(동일한 대화, 원본과 동일한 작성자), 편집 이전 텍스트가 아닌 편집된 내용과 인용 텍스트를 비교합니다. 메시지에 미리보기가 없거나 미리보기에 원본이 삽입되지 않은 경우 이 필드는 없습니다. Invalid 미리보기는 신뢰할 수 없는 것으로 간주하세요: 메시지 자체는 진짜이지만 인용된 자료는 그렇지 않습니다—인용은 오직 검증된 원본에서만 렌더링하세요. **encrypt / decrypt**는 대화 키로 UTF-8 메타데이터(예: 암호화된 그룹 이름)를 다룰 때 사용합니다—메시지 봉투용이 아닙니다. **encrypt_stream / decrypt_stream**은 첨부 파일 바이트를 암호화합니다. 미디어를 참고하세요. 저수준 **sign / verify / verify_key_binding**은 고급 흐름을 지원합니다. 대화 키 변경, 그룹 생성 및 멤버 추가는 prepare 메서드로 서명됩니다. encrypt_message / encrypt_reply에 전달하는 대화 ID는 보유하고 있는 어떤 형태든 가능합니다—이벤트의 A:B, 목록이나 URL 경로의 A-B(어떤 순서든), 또는 그저 수신자의 사용자 ID—SDK는 서명 전에 이를 정규화합니다. 그룹 ID(g 접두사)는 그대로 통과됩니다.

미디어 스트림

파일 바이트를 텍스트에 사용한 동일한 대화 키로 암호화하고, Chat 미디어 API를 통해 업로드한 뒤, encrypt_message에 **media_hash_key**를 첨부하세요. 이는 게시물 미디어 모델(expansions=attachments.media_keys)이 아닙니다. 전체 업로드/다운로드 흐름: 미디어.

대용량 미디어를 위한 점진적 스트리밍

대용량 파일의 경우, 전체 페이로드를 메모리에 유지하지 않도록 하세요: stream_encryptor() / stream_decryptor()StreamEncryptor / StreamDecryptor를 반환하며, 청크(각 약 1 MB)로 push(chunk)를 통해 공급한 다음 마지막에 finish()를 한 번 호출합니다. 복호화 시 finish()는 잘린 스트림을 감지합니다(최종 프레임 전에 입력이 끝나면 실패). 따라서 성공하기 전까지는 push된 평문을 완전한 것으로 취급하지 마세요.
JS/WASM에서만: finish()는 기본 WASM 객체를 소비하고 해제합니다. finish() 이후에는 절대 free()를 호출하지 마세요(예외 발생). 완료 에 스트림을 포기하는 경우에만(예: 오류 경로) free()를 호출하세요.

유틸리티

Base64/hex 헬퍼, MIME 스니핑, 이미지 크기 감지는 모듈 수준 함수(Python/JS/Rust/Go) 또는 ChatXdkUtilities(C#/Java)로 제공됩니다—추가 라이브러리 없이 첨부 파일 메타데이터를 구성할 때 유용합니다.

주요 타입

다음의 개념적 타입은 여러 언어에서 등장합니다(정확한 필드 이름은 다릅니다. JS는 종종 message와 같은 camelCase 이벤트 판별자를 사용합니다):
  • SendPayloadencrypt_message 및 다른 encrypt 헬퍼의 반환 값: SDK가 생성한 message_id(서명된 이벤트에 삽입된 UUID—메시지의 message_id로 전송하고 중복 제거를 위해 보관), encrypted_content, encoded_event_signature, 서명 메타데이터, conversation_key_version, should_notify. Chat API 전송 본문에 매핑하세요.
  • PublicKeyRegistrationPayload — 공개 키 추가 API를 위한 generate_keypairs / 공개 키 게터의 출력.
  • SigningKeyEntry — 서명 검증을 위해 복호화에 전달하거나 set_signing_keys를 통해 저장하는 발신자 공개 자료.
  • PreparedConversationChange — 세 prepare 메서드의 출력: 유도되거나 전달된 conversation_id, 원시 conversation_key 바이트, conversation_key_version, participant_keys(user_id, encrypted_key, public_key_version), action_signatures(message_id, encoded_message_event_detail, signature, signature_version, public_key_version, 선택적 signature_payload—키 변경 서명에서는 이 페이로드가 평문 키를 포함하기 때문에 생략됨).
  • DecryptEventsResult — 메시지, 선택적 오류, 그리고 추출된 conversation_keys. 답장을 인용하는 복호화된 메시지는 reply_preview_validation을 담고 있습니다(암호화 및 전송 헬퍼 참고).
전체 필드 목록은 chat-xdk 저장소의 언어별 스텁(docs/API.md, *.pyi, index.d.ts)을 사용하세요.

오류

Python은 일반적으로 설명이 포함된 메시지와 함께 **ValueError**를 발생시킵니다(예: 잘못된 패스코드). TypeScript/JavaScript는 **Error**를 던집니다. Go는 (value, error)를 반환합니다. 이력에는 **decrypt_events**를 선호하세요. 그러면 잘못된 이벤트 하나가 배치를 중단시키지 않습니다. 부분 실패는 errors 컬렉션을 검사하세요. 일부 검증 오류는 영구적입니다. 서명은 불변이며 이벤트 자체에서 서명된 페이로드를 재구축하여 검증됩니다. 따라서 signature missing or no matching signing key 또는 ECDSA 불일치로 실패한 오래된 이벤트는 이후 모든 로드에서 실패합니다—재시도, 키 갱신, API 호출로도 치유할 수 없습니다. 이는 일시적 오류가 아닌 툼스톤으로 취급하세요. 대화 키를 교체하면 그 시점부터 깨끗하고 검증 가능한 이력이 시작됩니다.

다음 단계

시작하기

Chat XDK를 Chat API에 연결하기

미디어

스트림 암호화 및 미디어 REST

실시간 이벤트

웹훅 및 활동 전달

문제 해결

자주 발생하는 실패