グループと 1:1 の違い
暗号処理は依然として: 鍵とペイロードには Chat XDK、グループの作成、参加者鍵ラップの公開、メッセージの送信、イベントのロードには X API です。
グループの作成と鍵の確立
POST /2/chat/conversations/group/initializeでグループ ID を発行します — レスポンスのdata.conversation_idは、以下のすべての箇所で使用する g プレフィックス付きの ID です。- 各メンバーの identity 公開鍵と
public_key_versionをロードします(Encryption keys の下にあるGET公開鍵ルート;GET /2/users/public_keysは複数のユーザーを 1 回のリクエストで取得します)。使用前に各レコードをverify_key_bindingで検証してください(Getting Started の警告を参照)。 prepare_group_createを、すべてのメンバー(自分自身を含む)、g プレフィックス付き ID、メンバー/管理者 ID リストとともに一度実行します。1 回の呼び出しで会話鍵を生成し、すべてのメンバー用にラップし、set_identityで設定したセッション ID で作成に署名します — 2 つのアクション署名(会話鍵の変更とグループ作成)を返します。POST /2/chat/conversations/groupに、グループのメンバー/管理者、conversation_key_version、conversation_participant_keys(SDKencrypted_key→ APIencrypted_conversation_key)、および両方のaction_signaturesを送信します。検証失敗は、安定した人間が読めるメッセージとして返されます。たとえば"Too many members: adding these members would exceed the allowed group size."や"Cannot add all members: one or more of the requested members cannot be added to this conversation."です。- 暗号化/復号のために、未加工の会話鍵とバージョンを保持します。
prepare_group_create に渡す title と avatar_url は署名され、グループ作成イベントにそのまま埋め込まれます。サーバーはリクエストに対してそれらを照合します — したがって、POST ボディの group_name / group_avatar_url の値は SDK に渡したものとバイト単位で同一でなければなりません。そうでなければ、呼び出しは署名検証に失敗します。
- Python
- TypeScript
- Rust
- Go
- C#
- Java
message_id、encoded_message_event_detail、ネストされた message_event_signature)は、Getting Started — conversation keys の鍵 POST と同じです。
メンバーシップが変更されたときは、prepare_group_members_change を新しいメンバー ID と現在のロスター(メンバー、管理者、保留中のメンバー、および設定されている場合は現在のタイトル/アバター/TTL)とともに呼び出します。会話鍵をローテーションし、グループ作成と同様に2 つのアクション署名を返します — すべてを add members(POST /2/chat/conversations/{id}/members)に POST します。その後、鍵変更トラフィックが期待されます: Getting Started の鍵ローテーション のように扱います(extract_conversation_keys / decrypt_events、その後最新バージョンで暗号化)。
prepare_group_members_change は、渡したロスターにのみラップされた新しい会話鍵を生成するため、新しいメンバーは新しい鍵バージョンを受け取り、以前のバージョンで送信されたメッセージを復号できません。その逆は真ではありません: ローテーションは以前のバージョンへのアクセスを取り消しません — 古い鍵をすでに持っている人は、その下で暗号化されたメッセージを読み続けることができます。会話鍵が漏洩したと疑われる場合は、prepare_conversation_key_change でローテーションしてください;これは将来のメッセージのみを保護します。
暗号化されたグループメタデータ
一部の会話フィールド(たとえば表示名やアバター URL)は、会話鍵で暗号化された状態で到着することがあります。これはencrypt_message ではありません。汎用の Chat XDK encrypt / decrypt のペア(UTF-8 文字列入力、base64 暗号文出力、未加工の会話鍵を使用)です。
特定のフィールドが暗号化されて保存されるかどうかは、それを書き込むクライアントによって決定されます: prepare_group_create は、提供されたとおりにタイトルに署名して送信します(会話鍵はその呼び出しが生成するまで存在しないため、作成時のタイトルはその下で暗号化できません)。フィールドが暗号文である会話を読むときは、フィールドが書き込まれたときにアクティブだった鍵バージョンで decrypt して復号します。
- Python
- TypeScript
- Rust
- Go
- C#
- Java
メッセージとイベント
グループでの送受信は、未加工の会話鍵を持てば 1:1 と同じです:- 送信:
encrypt_message→ メッセージ送信 API(Getting Started) - 受信: イベント API またはリアルタイム配信 →
decrypt_event/decrypt_events - メディア: グループの会話 ID を使った Media
離脱したメンバーによる鍵変更
グループの鍵変更イベントは、それを実行した人 — 多くの場合は作成者または管理者 — によって署名されます。そのメンバーが後でグループを離脱した(またはアカウントを無効化した)場合、公開鍵エンドポイントはそのメンバーの鍵を返さなくなるため、検証済みの復号パス(署名鍵付きのdecrypt_events)はそれらの鍵変更イベントで signature missing or no matching signing key で失敗します。イベントは壊れていません;検証素材が単に配信されなくなっただけです。
長命なグループはこれを想定し、検証できない鍵変更イベントについては extract_conversation_keys にフォールバックする必要があります。このパスは署名チェックをスキップし、あなたの identity 鍵で復号することによって会話鍵を回復します。セキュリティモデルは以下の理由で維持されます:
- あなたの identity 鍵に暗号化された鍵素材のみが回復可能です — 第三者があなたが読める鍵を注入することはできません
- すべてのメッセージは依然として送信者ごとに署名検証されるため、メッセージの作成者情報には影響しません
decrypt_events(set_cache_keys(true) が有効な場合、SDK の鍵キャッシュにも供給されます)を使用し、それが拒否した鍵変更イベントに対してのみ extract_conversation_keys を使ってください。
チェックリスト
POST /2/chat/conversations/group/initializeで g プレフィックス付き ID を発行する- すべてのメンバーで
prepare_group_create;参加者鍵ラップと両方のアクション署名をPOST /2/chat/conversations/groupに POST する - 未加工の鍵 + バージョンをキャッシュ;鍵変更イベントで更新する
- メンバーシップ変更時は
prepare_group_members_change(2 つの署名)→POST /2/chat/conversations/{id}/members - フィールドが暗号文の場合は
decryptでグループメタデータを復号する - 1:1 と同じパターンで送受信する