diff --git a/es/xchat/cryptography-primer.mdx b/es/xchat/cryptography-primer.mdx
index 33d391594..0c7b3cb71 100644
--- a/es/xchat/cryptography-primer.mdx
+++ b/es/xchat/cryptography-primer.mdx
@@ -64,7 +64,7 @@ X Chat usa tres tipos de material de claves, cada uno con un propósito específ
Cuando alguien te agrega a una conversación, cifra la clave de conversación usando tu clave pública de identidad. Solo tu clave privada de identidad puede descifrarla.
-Las mitades públicas se registran y descubren a través de las APIs de **claves públicas** de la plataforma (consulta Encryption keys en la referencia de la API). Las mitades privadas permanecen dentro del Chat XDK (por ejemplo, mediante la [copia de seguridad segura de claves](#copia-de-seguridad-segura-de-claves-almacenamiento-distribuido-de-claves) o un blob de claves cuidadosamente protegido).
+Las mitades públicas se registran y descubren a través de las APIs de **clave pública** de la plataforma (consulta Encryption keys en la referencia de la API). Las mitades privadas permanecen dentro del Chat XDK (por ejemplo, mediante la [copia de seguridad segura de claves](#copia-de-seguridad-segura-de-claves-almacenamiento-distribuido-de-claves) o un blob de claves cuidadosamente protegido).
### 2. Par de claves de firma
@@ -75,7 +75,7 @@ Las mitades públicas se registran y descubren a través de las APIs de **claves
| **Clave pública de firma** | Se comparte con otros; se usa para verificar tus firmas |
| **Clave privada de firma** | Se mantiene en secreto; se usa para firmar tus mensajes |
-Cuando envías un mensaje, se firma con tu clave privada de firma. Los destinatarios verifican usando tu clave pública de firma (también publicada mediante las APIs de claves públicas). El Chat XDK firma como parte del cifrado de un mensaje y puede verificar al descifrar cuando proporcionas el material de clave pública del remitente.
+Cuando envías un mensaje, se firma con tu clave privada de firma. Los destinatarios verifican usando tu clave pública de firma (también publicada mediante las APIs de clave pública). El Chat XDK firma como parte del cifrado de un mensaje y puede verificar al descifrar cuando proporcionas el material de clave pública del remitente.
### 3. Clave de conversación
@@ -88,7 +88,7 @@ Cuando envías un mensaje, se firma con tu clave privada de firma. Los destinata
| **Compartida entre participantes** | Todos los participantes que deberían leer la conversación tienen una copia |
| **Versionada** | Las claves pueden rotarse; las apps deberían llevar registro de las versiones a lo largo del tiempo |
-Las claves de conversación se generan cuando se configura una conversación o cuando las claves rotan. Cada participante recibe una **copia cifrada** de la clave, producida con su clave pública de identidad. Después de descifrar tu copia una vez, conservas la clave de conversación **en bruto** y la usas para cifrar mensajes (y [multimedia](/xchat/media)) de forma rápida. La configuración de esas copias para una conversación se hace mediante el Chat XDK junto con los endpoints de **claves** de conversación—se recorre en [Primeros pasos](/xchat/getting-started#4-set-up-conversation-keys).
+Las claves de conversación se generan cuando se configura una conversación o cuando las claves rotan. Cada participante recibe una **copia cifrada** de la clave, producida con su clave pública de identidad. Después de descifrar tu copia una vez, conservas la clave de conversación **en bruto** y la usas para cifrar mensajes (y [multimedia](/xchat/media)) de forma rápida. La configuración de esas copias para una conversación se hace mediante el Chat XDK junto con los endpoints de **clave** de conversación—se recorre en [Primeros pasos](/xchat/getting-started#4-set-up-conversation-keys).
---
@@ -143,9 +143,9 @@ Un desafío central del cifrado de extremo a extremo es la **distribución de cl
Cuando se prepara una conversación para mensajería:
-1. Se genera una clave de conversación aleatoria (en el Chat XDK)
-2. Para **cada participante**, esa clave se cifra dirigida a su **clave pública de identidad**
-3. Esas copias cifradas se almacenan y entregan mediante las APIs de Chat de X
+1. El Chat XDK genera una clave de conversación aleatoria
+2. El Chat XDK cifra esa clave dirigida a la **clave pública de identidad de cada participante**
+3. Tu app publica esas copias cifradas a través de las APIs de Chat de X
4. Cada participante descifra **su** copia con su clave privada de identidad (en el Chat XDK)
X solo manipula las copias **envueltas**, nunca la clave de conversación en bruto.
@@ -166,7 +166,7 @@ Tu app debería:
## Copia de seguridad segura de claves: almacenamiento distribuido de claves
-Tus claves **privadas** de identidad y firma deben almacenarse con cuidado. X Chat incluye un sistema de **copia de seguridad segura de claves** (implementado con Juicebox) para que las claves puedan recuperarse con un código de acceso entre dispositivos sin darle a ningún servidor el secreto completo.
+Tus claves **privadas** de identidad y firma deben almacenarse con cuidado. X Chat incluye un sistema de **copia de seguridad segura de claves** para que las claves puedan recuperarse con un código de acceso entre dispositivos sin darle a ningún servidor el secreto completo.
### El problema con el almacenamiento tradicional de claves
@@ -201,7 +201,7 @@ flowchart LR
Obtienes recuperabilidad (nuevo dispositivo + código de acceso) sin que una sola parte tenga el secreto completo.
-No configuras servidores de copia de seguridad de claves a mano para el flujo normal. El Chat XDK incluye el cliente de copia de seguridad; la configuración de realms proviene de la X API como **`juicebox_config`** en tu registro de clave pública (el campo lleva el nombre de Juicebox, la implementación subyacente). El almacenamiento del código de acceso por primera vez y el desbloqueo posterior son llamadas del Chat XDK—consulta [inicializar con claves existentes](/xchat/getting-started#2-initialize-the-chat-xdk-with-existing-keys) y [crear y registrar las claves](/xchat/getting-started#3-create-and-register-keys-first-time-setup) en Primeros pasos. Algunas apps (especialmente servidores y bots) usan un blob de claves exportado en lugar de la copia de seguridad segura de claves; protege ese material como una contraseña.
+No configuras servidores de copia de seguridad de claves a mano para el flujo normal. El Chat XDK incluye el cliente de copia de seguridad; la configuración de realms proviene de la X API como el campo **`juicebox_config`** en tu registro de clave pública. El almacenamiento del código de acceso por primera vez y el desbloqueo posterior son llamadas del Chat XDK—consulta [inicializar con claves existentes](/xchat/getting-started#2-initialize-the-chat-xdk-with-existing-keys) y [crear y registrar las claves](/xchat/getting-started#3-create-and-register-keys-first-time-setup) en Primeros pasos. Algunas apps (especialmente servidores y bots) usan un blob de claves exportado en lugar de la copia de seguridad segura de claves; protege ese material como una contraseña.
---
@@ -224,7 +224,7 @@ Si algo cambia en el material firmado, la verificación falla. Solo alguien con
### En tu app
-El Chat XDK firma cuando cifras mensajes salientes y verifica cuando descifras mensajes entrantes contra el material de clave pública del remitente (obtenido de las APIs de claves públicas). La verificación es **obligatoria por defecto**: el SDK rechaza los eventos firmados no verificados a menos que desactives explícitamente la comprobación (no recomendado). Los detalles están en la referencia del [Chat XDK](/xchat/xchat-xdk).
+El Chat XDK firma cuando cifras mensajes salientes y verifica cuando descifras mensajes entrantes contra el material de clave pública del remitente (obtenido de las APIs de clave pública). La verificación es **obligatoria por defecto**: el SDK rechaza los eventos firmados no verificados a menos que desactives explícitamente la comprobación (no recomendado). Los detalles están en la referencia del [Chat XDK](/xchat/xchat-xdk).
### Cambios de estado firmados (firmas de acción)
@@ -264,11 +264,11 @@ Las firmas están vinculadas al contenido del evento y son inmutables: un evento
| Término | Definición |
|:--------|:-----------|
| **Cifrado simétrico** | Misma clave cifra y descifra (se usa para mensajes y flujos de multimedia) |
-| **Cifrado asimétrico** | Claves distintas para cifrar y descifrar (se usa para envolver claves de conversación) |
+| **Cifrado asimétrico** | Claves distintas para cifrar y descifrar (se usa para intercambiar claves de conversación) |
| **Clave pública** | Es seguro compartirla; se usa para cifrar *hacia* alguien o verificar sus firmas |
| **Clave privada** | Debe permanecer secreta; se usa para descifrar o firmar |
| **Par de claves** | Una clave pública y una clave privada vinculadas |
-| **ECDH / ECIES** | Algoritmos usados al envolver claves de conversación hacia claves de identidad |
+| **ECDH / ECIES** | Algoritmos usados al intercambiar claves de conversación mediante claves de identidad |
| **ECDSA** | Algoritmo de firma usado para la autoría de mensajes |
| **P-256** | Curva elíptica usada en X Chat (secp256r1) |
| **Clave de conversación** | Clave simétrica compartida por los participantes en una conversación (versionada a lo largo del tiempo) |
diff --git a/es/xchat/getting-started.mdx b/es/xchat/getting-started.mdx
index 5fea0a354..4d15ed22f 100644
--- a/es/xchat/getting-started.mdx
+++ b/es/xchat/getting-started.mdx
@@ -45,11 +45,10 @@ Las apps de X Chat usan dos piezas juntas:
```toml
[dependencies]
# chat-xdk-core is not yet on crates.io — use the git dependency
- chat-xdk-core = { git = "https://github.com/xdevplatform/chat-xdk", tag = "v0.2.1" }
+ chat-xdk-core = { git = "https://github.com/xdevplatform/chat-xdk", tag = "v0.4.0" }
reqwest = { version = "0.12", features = ["blocking", "json"] }
serde_json = "1"
base64 = "0.22"
- uuid = { version = "1", features = ["v4"] }
# Required until thrift 0.24 is released on crates.io
[patch.crates-io]
@@ -75,7 +74,7 @@ Las apps de X Chat usan dos piezas juntas:
com.x
chatxdk
- 0.2.1
+ 0.4.0
```
@@ -133,14 +132,14 @@ Crea un cliente de API con tu token de acceso OAuth 2.0 de **usuario**:
## 2. Inicializa el Chat XDK con claves existentes
-Este paso **carga claves que ya tienes**—úsalo cuando esta identidad ya completó la configuración inicial:
+Este paso **carga claves que ya tienes**—úsalo cuando esta identidad ya completó la configuración inicial antes:
- **Copia de seguridad segura de claves:** construye el SDK con el `juicebox_config` de tu registro de clave pública y luego usa `unlock` con tu código de acceso para recuperar las claves privadas (por ejemplo, en un dispositivo nuevo).
-- **Blob de claves:** `import_keys` con un blob que exportaste previamente mediante `export_keys`.
+- **Blob de claves:** `import_keys` con un blob que exportaste previamente mediante `export_keys`, pasando la versión registrada de la clave junto con él (Rust y Go llaman a esta variante `import_keys_with_version` / `ImportKeysWithVersion`).
-Después establece la versión de tu clave pública registrada (`public_key_version` en tu registro).
+Después llama a **`set_identity(user_id, signing_key_version)`** una vez, con tu ID de usuario y el `public_key_version` de tu registro. Esto guarda la identidad de sesión: cada llamada posterior a encrypt y prepare firma como esta identidad, así que nunca pasas un ID de remitente ni una versión de clave de firma por llamada.
-**¿Configuras por primera vez?** Construye el SDK de la misma forma pero omite `unlock`/`import_keys` y continúa en el [paso 3](#3-crea-y-registra-las-claves-configuracion-inicial) para crear, respaldar y registrar tus claves.
+**¿Configuras por primera vez?** Construye el SDK de la misma forma pero omite `unlock`/`import_keys` y continúa en el [paso 3](#3-create-and-register-keys-first-time-setup) para crear, respaldar y registrar tus claves.
@@ -160,7 +159,9 @@ Después establece la versión de tu clave pública registrada (`public_key_vers
chat = Chat(json.dumps(record["juicebox_config"]))
chat.unlock("YOUR_PASSCODE") # recovers keys stored by setup() during first-time setup (step 3)
- chat.set_key_version(signing_key_version)
+ # Or load a key blob instead of secure key backup:
+ # chat.import_keys(blob, version=signing_key_version)
+ chat.set_identity("YOUR_USER_ID", signing_key_version)
```
@@ -181,7 +182,7 @@ Después establece la versión de tu clave pública registrada (`public_key_vers
getAuthToken: async (realmId) => getRealmTokenFromYourBackend(realmId),
});
await chat.unlock('YOUR_PASSCODE');
- chat.setKeyVersion(signingKeyVersion);
+ chat.setIdentity('YOUR_USER_ID', signingKeyVersion);
```
@@ -189,11 +190,11 @@ Después establece la versión de tu clave pública registrada (`public_key_vers
use base64::{engine::general_purpose::STANDARD as B64, Engine};
use chat_xdk_core::ChatCore;
- let mut chat = ChatCore::new();
+ let chat = ChatCore::new();
let blob = B64.decode(std::env::var("PRIVATE_KEYS_B64")?)?;
let signing_key_version = std::env::var("SIGNING_KEY_VERSION").unwrap_or_else(|_| "1".into());
- chat.import_keys(&blob)?;
- chat.set_key_version(&signing_key_version);
+ chat.import_keys_with_version(&blob, &signing_key_version)?;
+ chat.set_identity("YOUR_USER_ID", &signing_key_version);
```
@@ -207,14 +208,16 @@ Después establece la versión de tu clave pública registrada (`public_key_vers
if err != nil {
log.Fatal(err)
}
- if err := chat.ImportKeys(blob); err != nil {
- log.Fatal(err)
- }
signingKeyVersion := os.Getenv("SIGNING_KEY_VERSION")
if signingKeyVersion == "" {
signingKeyVersion = "1"
}
- chat.SetKeyVersion(signingKeyVersion)
+ if err := chat.ImportKeysWithVersion(blob, signingKeyVersion); err != nil {
+ log.Fatal(err)
+ }
+ if err := chat.SetIdentity(myUserID, signingKeyVersion); err != nil {
+ log.Fatal(err)
+ }
```
@@ -224,8 +227,8 @@ Después establece la versión de tu clave pública registrada (`public_key_vers
using var chat = new Chat();
var signingKeyVersion = Environment.GetEnvironmentVariable("SIGNING_KEY_VERSION") ?? "1";
chat.ImportKeys(Convert.FromBase64String(
- Environment.GetEnvironmentVariable("PRIVATE_KEYS_B64")!));
- chat.SetKeyVersion(signingKeyVersion);
+ Environment.GetEnvironmentVariable("PRIVATE_KEYS_B64")!), signingKeyVersion);
+ chat.SetIdentity(myUserId, signingKeyVersion);
```
@@ -234,8 +237,8 @@ Después establece la versión de tu clave pública registrada (`public_key_vers
String signingKeyVersion = Optional.ofNullable(System.getenv("SIGNING_KEY_VERSION")).orElse("1");
try (Chat chat = new Chat()) {
- chat.importKeys(Base64.getDecoder().decode(System.getenv("PRIVATE_KEYS_B64")));
- chat.setKeyVersion(signingKeyVersion);
+ chat.importKeys(Base64.getDecoder().decode(System.getenv("PRIVATE_KEYS_B64")), signingKeyVersion);
+ chat.setIdentity(myUserId, signingKeyVersion);
}
```
@@ -244,18 +247,24 @@ Después establece la versión de tu clave pública registrada (`public_key_vers
Los ejemplos para servidor y bot suelen usar un **blob de claves** (`export_keys` / `import_keys`). Las apps cliente suelen usar la **copia de seguridad segura de claves** (`setup` / `unlock` con un código de acceso). Consulta la referencia del [Chat XDK](/xchat/xchat-xdk) para ambos caminos.
-**¿Traes tus propias claves?** `import_keys` solo acepta el blob opaco que produce `export_keys` del Chat XDK—es una serialización privada y versionada del estado completo de las claves, no claves P-256 en bruto ni codificadas en PEM. No puedes construir este blob por tu cuenta: genera las claves con `generate_keypairs` ([paso 3](#3-crea-y-registra-las-claves-configuracion-inicial)), exporta el blob una vez y guárdalo codificado en base64. Los blobs hechos a mano o modificados fallan al importarse.
+**¿Traes tus propias claves?** `import_keys` solo acepta el blob opaco que produce `export_keys` del Chat XDK—es una serialización privada y versionada del estado completo de las claves, no claves P-256 en bruto ni codificadas en PEM. No puedes construir este blob por tu cuenta: genera las claves con `generate_keypairs` ([paso 3](#3-create-and-register-keys-first-time-setup)), exporta el blob una vez y guárdalo codificado en base64. Los blobs hechos a mano o modificados fallan al importarse.
---
## 3. Crea y registra las claves (configuración inicial)
-Omite este paso si cargaste claves existentes en el [paso 2](#2-inicializa-el-chat-xdk-con-claves-existentes). De lo contrario, la configuración inicial de una identidad nueva hace **tres cosas**:
+Omite este paso si cargaste claves existentes en el [paso 2](#2-initialize-the-chat-xdk-with-existing-keys). De lo contrario, la configuración inicial de una identidad nueva hace **tres cosas**:
1. **Crear los pares de claves** — `generate_keypairs` produce los pares de claves de identidad y de firma.
-2. **Registrar las claves públicas** — envía el payload de registro con POST al endpoint add-public-key para que otros puedan cifrar hacia ti y verificar tus firmas.
-3. **Guardar las claves privadas** — `setup` con un código de acceso las escribe en la copia de seguridad segura de claves (clientes), o `export_keys` devuelve un blob de claves para que lo guardes de forma segura (servidores y bots).
+2. **Guardar las claves privadas** — `setup` con un código de acceso las escribe en la copia de seguridad segura de claves (clientes), o `export_keys` devuelve un blob de claves para que lo guardes de forma segura (servidores y bots).
+3. **Registrar las claves públicas** — envía el payload de registro con POST al endpoint add-public-key para que otros puedan cifrar hacia ti y verificar tus firmas.
+
+Termina llamando a `set_identity` con la versión de clave del registro, para que esta sesión firme como la nueva identidad.
+
+
+Los scripts listos para ejecutar de registro por única vez para cada binding viven en [`chat-xdk/examples`](https://github.com/xdevplatform/chat-xdk/tree/main/examples) (Python, TypeScript, Go, Rust, C# y Java). Úsalos en vez de armar a mano el flujo de abajo cuando solo necesitas incorporar una nueva identidad.
+
@@ -280,7 +289,7 @@ Omite este paso si cargaste claves existentes en el [paso 2](#2-inicializa-el-ch
),
)
chat.setup("YOUR_PASSCODE")
- chat.set_key_version(str(registration.version or signing_key_version))
+ chat.set_identity("YOUR_USER_ID", str(registration.version or "1"))
```
@@ -300,7 +309,7 @@ Omite este paso si cargaste claves existentes en el [paso 2](#2-inicializa-el-ch
generate_version: registration.generateVersion,
});
await chat.setup('YOUR_PASSCODE');
- chat.setKeyVersion(String(registration.version ?? signingKeyVersion));
+ chat.setIdentity('YOUR_USER_ID', String(registration.version ?? '1'));
```
@@ -316,6 +325,8 @@ Omite este paso si cargaste claves existentes en el [paso 2](#2-inicializa-el-ch
anyhow::bail!("register keys: {}", resp.text()?);
}
let _blob = chat.export_keys()?; // store securely
+ let key_version = registration.version.clone().unwrap_or_else(|| "1".into());
+ chat.set_identity(&user_id, &key_version);
```
@@ -335,9 +346,15 @@ Omite este paso si cargaste claves existentes en el [paso 2](#2-inicializa-el-ch
log.Fatal(err)
}
resp.Body.Close()
- privateKeysB64, _ := chat.ExportKeys() // store securely
- _ = privateKeysB64
- chat.SetKeyVersion(signingKeyVersion)
+ privateKeys, _ := chat.ExportKeys() // store securely
+ _ = privateKeys
+ keyVersion := "1"
+ if registration.Version != nil {
+ keyVersion = *registration.Version
+ }
+ if err := chat.SetIdentity(userID, keyVersion); err != nil {
+ log.Fatal(err)
+ }
```
@@ -349,7 +366,7 @@ Omite este paso si cargaste claves existentes en el [paso 2](#2-inicializa-el-ch
$"https://api.x.com/2/users/{Uri.EscapeDataString(userId)}/public_keys", content);
regResp.EnsureSuccessStatusCode();
var blob = chat.ExportKeys(); // store securely
- chat.SetKeyVersion(signingKeyVersion);
+ chat.SetIdentity(userId, registration.Version ?? "1");
```
@@ -367,7 +384,7 @@ Omite este paso si cargaste claves existentes en el [paso 2](#2-inicializa-el-ch
throw new RuntimeException("register keys: " + regResp.body());
}
byte[] blob = chat.exportKeys(); // store securely
- chat.setKeyVersion(signingKeyVersion);
+ chat.setIdentity(myUserId, registration.version != null ? registration.version : "1");
```
@@ -380,7 +397,7 @@ Usa un código de acceso fuerte para la copia de seguridad segura de claves. Per
## 4. Configura las claves de conversación
-Llama a **`prepare_conversation_key_change`** con tu ID de usuario, tu versión de clave de firma y la clave pública de identidad de cada participante. Una sola llamada genera una nueva clave de conversación, la cifra para cada participante y firma el cambio. Envía el resultado con POST al endpoint **add conversation keys** (`POST /2/chat/conversations/{id}/keys`)—el cuerpo necesita `conversation_key_version`, `conversation_participant_keys` (SDK `encrypted_key` → API `encrypted_conversation_key`) y **`action_signatures`** (obligatorio; la API rechaza la llamada sin ellas). Conserva la clave de conversación **en bruto** para enviar.
+Llama a **`prepare_conversation_key_change`** con la clave pública de identidad de cada participante; la identidad del remitente proviene de la sesión que estableciste en el paso 2. Una sola llamada genera una nueva clave de conversación, la cifra para cada participante y firma el cambio. Envía el resultado con POST al endpoint **add conversation keys** (`POST /2/chat/conversations/{id}/keys`)—el cuerpo necesita `conversation_key_version`, `conversation_participant_keys` (SDK `encrypted_key` → API `encrypted_conversation_key`) y **`action_signatures`** (obligatorio; la API rechaza la llamada sin ellas). Conserva la clave de conversación **en bruto** para enviar.
La respuesta devuelve el id canónico de la conversación (`data.conversation_id`—el par unido con guión para un 1:1, o el id con prefijo `g` para un grupo) y el `data.sequence_id` del cambio de clave. Usa ese id devuelto para solicitudes posteriores en lugar de reconstruirlo en el cliente. La misma llamada también **rota** las claves más adelante: pasa el id de conversación existente a `prepare_conversation_key_change` y haz POST con la versión de clave más reciente. Rota cuando sospeches que la clave de conversación quedó expuesta—la rotación protege **mensajes futuros** únicamente; los mensajes cifrados bajo versiones anteriores de la clave siguen siendo legibles para cualquiera que tenga esas versiones.
@@ -398,8 +415,6 @@ La respuesta devuelve el id canónico de la conversación (`data.conversation_id
return {"user_id": user_id, "public_key": r["public_key"], "key_version": r["public_key_version"]}
prepared = chat.prepare_conversation_key_change(
- "YOUR_USER_ID",
- signing_key_version,
[public_key_input("YOUR_USER_ID"), public_key_input("RECIPIENT_USER_ID")],
# conversation_id=None for a new 1:1; pass the id to rotate later
)
@@ -446,8 +461,6 @@ La respuesta devuelve el id canónico de la conversación (`data.conversation_id
// Omit conversationId for a new 1:1; pass the id to rotate later
const prepared = chat.prepareConversationKeyChange({
- senderId: 'YOUR_USER_ID',
- signingKeyVersion,
publicKeys: [
await publicKeyInput('YOUR_USER_ID'),
await publicKeyInput('RECIPIENT_USER_ID'),
@@ -480,9 +493,9 @@ La respuesta devuelve el id canónico de la conversación (`data.conversation_id
```rust
// public_key_inputs: Vec from GET public keys
// (user_id, public_key, key_version ← public_key_version)
- // new 1:1; set params.conversation_id = Some(id) to rotate later
+ // New 1:1; set params.conversation_id = Some(id) to rotate later
let prepared = chat.prepare_conversation_key_change(
- ConversationKeyChangeParams::new(&sender_id, &signing_key_version, public_key_inputs),
+ ConversationKeyChangeParams::new(public_key_inputs),
)?;
let participant_keys: Vec<_> = prepared
.participant_keys
@@ -532,8 +545,6 @@ La respuesta devuelve el id canónico de la conversación (`data.conversation_id
```go
// KeyVersion comes from the public_key_version field on each record
prepared, err := chat.PrepareConversationKeyChange(chatxdk.ConversationKeyChangeParams{
- SenderID: myUserID,
- SigningKeyVersion: signingKeyVersion,
PublicKeys: []chatxdk.PublicKeyInput{
{UserID: myUserID, PublicKey: myIdentityPubB64, KeyVersion: myKeyVersion},
{UserID: recipientID, PublicKey: theirIdentityPubB64, KeyVersion: theirKeyVersion},
@@ -572,21 +583,18 @@ La respuesta devuelve el id canónico de la conversación (`data.conversation_id
req.Header.Set("Content-Type", "application/json")
resp, err := httpClient.Do(req)
// Response data.conversation_id is the canonical id for later requests
- // prepared.ConversationKey feeds EncryptMessage
_ = resp
+ convKey := prepared.ConversationKey
+ convKeyVersion := prepared.ConversationKeyVersion
```
```csharp
// KeyVersion comes from the public_key_version field on each record
- var prepared = chat.PrepareConversationKeyChange(new ConversationKeyChangeParams {
- SenderId = myUserId,
- SigningKeyVersion = signingKeyVersion,
- PublicKeys = new[] {
- new PublicKeyInput { UserId = myUserId, PublicKey = myPk, KeyVersion = myVer },
- new PublicKeyInput { UserId = recipientId, PublicKey = theirPk, KeyVersion = theirVer },
- },
- }); // ConversationId null for a new 1:1; pass the id to rotate later
+ var prepared = chat.PrepareConversationKeyChange(new ConversationKeyChangeParams(new[] {
+ new PublicKeyInput { UserId = myUserId, PublicKey = myPk, KeyVersion = myVer },
+ new PublicKeyInput { UserId = recipientId, PublicKey = theirPk, KeyVersion = theirVer },
+ })); // ConversationId null for a new 1:1; set it to rotate later
var keysBody = new {
conversation_key_version = prepared.ConversationKeyVersion,
conversation_participant_keys = prepared.ParticipantKeys.Select(pk => new {
@@ -625,12 +633,9 @@ La respuesta devuelve el id canónico de la conversación (`data.conversation_id
PublicKeyInput theirs = new PublicKeyInput();
theirs.userId = recipientId; theirs.publicKey = theirIdentityPubB64; theirs.keyVersion = theirKeyVersion;
- ConversationKeyChangeParams keyParams = new ConversationKeyChangeParams();
- keyParams.senderId = myUserId;
- keyParams.signingKeyVersion = signingKeyVersion;
- keyParams.publicKeys = List.of(mine, theirs);
- // keyParams.conversationId null for a new 1:1; set the id to rotate later
- PreparedConversationChange prepared = chat.prepareConversationKeyChange(keyParams);
+ // conversationId stays null for a new 1:1; set it to rotate later
+ PreparedConversationChange prepared =
+ chat.prepareConversationKeyChange(new ConversationKeyChangeParams(List.of(mine, theirs)));
List