Handling Sessions(会话处理)

当用户首次连接至 Backpack 时,Backpack 会返回一个 session 参数,表示用户的连接。所有后续的 Provider 方法中,应用应传递该 session 参数。应用需要负责存储该 session。

会话不会过期。用户与 Backpack 连接后,相应的应用可以无限期地发起请求,如 SignAndSendTransactionSignMessage,而无需重新提示用户连接 Backpack。

如果发生 Disconnect 事件或 Invalid Session 错误,应用仍然需要重新连接 Backpack。

会话结构

整个 session 参数采用 base58 编码。一个 session 应包含以下数据:

  • JSON 数据签名:一个 64 字节的 base58 编码签名,Backpack 会检查该签名是否与实际签署的消息一致。

  • JSON 数据:一个 JSON 对象,包含以下字段:

{
  "app_url": "string", // 用于获取应用元数据(例如标题、图标)的 URL
  "timestamp": "number", // 用户批准连接的时间戳。当前,session 不会过期
  "chain": "string", // 用户在连接时使用的链
  "cluster": "string" (可选) // 应用与用户初始连接时批准的网络集群
}

会话解码

Backpack 会在每次请求时解码和验证 session 参数。解码时,Backpack 使用 bs58 对其进行解码,去掉前 64 字节的签名部分,剩余部分当作 JSON 数据进行处理。

接着,Backpack 使用相同的密钥对 JSON 数据进行签名,并与 session 中的签名进行比较。如果签名一致,则 session 为有效。否则,认为 session 被篡改,签名不匹配。

通过 nacl.sign.open 可以便捷地验证并返回原始对象。详细信息请参考Encryption Resources

一旦验证 session 为有效,仍需确保 JSON 数据与预期一致。应用可能会提供公钥 A 的 session,但用户当前可能在 Backpack 使用的是公钥 B。在这种情况下,该 session 不应允许应用请求签名。

如果发生此情况,应用必须发起新的连接请求,或者使用正确的 session。

// 会话编码示例
const privateKey = ...;
const sessionData = JSON.stringify({
  "app_id": "APP_ID",
  "chain": "CHAIN",
  "cluster": "CLUSTER",
  "timestamp": 1644954984,
});
const bytes = Buffer.from(sessionData, "utf-8");

// tweetnacl-js 格式的签名 <signature><sessionData>
const signature = bs58.encode(nacl.sign(bytes, privateKey));

// 解码会话示例
const publicKey = ...;
const verifiedSessionData = nacl.sign.open(bs58.decode(signature), publicKey.toBytes());
if (!verifiedSessionData) throw new Error(`此会话并非由 ${publicKey} 签署`);

无效的 Session

尽管 session 不会过期,但有多种原因会导致 session 被认为是无效的:

  1. 它并非由当前的钱包密钥对签署。这可能意味着 session 完全是伪造的,或者它是由用户钱包中其他密钥对签署的。

  2. 它由当前钱包密钥对签署,但 session 的 JSON 数据存在问题。可能的原因包括:

    • 用户切换了链(或网络)。

    • app_url 被恶意阻止。

Last updated