@cubist-labs/cubesigner-sdk

中文文档
0.4.284发布于 2026/09/09MIT OR Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 1.9万

立方体符号类型SDK

中文使用文档
文档目录23 节
  1. 立方体符号背景
  2. 安装 SDK
  3. 登录到立方体符号
  4. 开始
  5. 证据 CubeSignerClient
  6. 获取 User 财务报告和审定财务报表 Org 资讯
  7. 创建一个 Key
  8. 签名 Ethereum 交易
  9. 使用醚.js而不是直接使用 SDK
  10. 访问控制 Role
  11. 制定安全政策
  12. 签个字
  13. 会话管理
  14. 从磁盘上装入
  15. 从内存装入
  16. 管理人员、储存和刷新
  17. 为 OIDC 用户创建会话
  18. 为用户设置 TOTP
  19. 配置用于签名的外交部政策
  20. 清理
  21. 建造SDK
  22. 运行 SDK 测试
  23. 许可证

立方体符号类型SDK

CubeSigner是一个硬件支持的非拘禁平台 安全 管理加密密钥。 此寄存器是用于 与 CubeSigner 服务进行方案互动.

立方体符号背景

小熊队 构建用于解决密钥的 CubeSigner 安全与关键可用性权衡:现在,许多团队被迫保留 内存中可用的密钥, 并因此暴露给攻击者, 或者试图保留 钥匙安全——通常只在休息时使用——费用高昂. CubeSigner 通过给开发人员低纬度访问来解决这个问题 硬件支持密钥生成和签名. 在所有这些行动中, CubeSigner 在由 MSM 封存的硝基飞地保护用户的密钥- 组合 带有热钱包速度和简便的冷钱包安全.

现在 CubeSigner SDK 支持像 Ethereum 这样的 EVM 链的签名 和雪崩, 以及非EVM链 比特币和索拉纳。 支持更多的链条 是在作品中!

安装 SDK

您可以从 npm 安装 SDK :

npm install --save "@cubist-labs/cubesigner-sdk"
npm install --save "@cubist-labs/cubesigner-sdk-fs-storage" # support for filesystem-backed sessions

登录到立方体符号

在运行下面的“ 启动” 示例( 或稍后的测试) 之前, 您必须 使用 cs 命令行工具,例如,

cs login [email protected] --env '<gamma|prod|...>'

开始

[TIP] 用于从 v0.3.* 改为 v0.4.*请看 移民.md

在这个节目中,我们要穿过一个简单的立方体符号 设置。 我们会制作一个签名钥匙 然后签署一些EVM 交易,然后添加一项安全政策,以限制 允许 CubeSigner 签名的交易.

开始,我们立即攻克高层 CubeSignerClient 类从一个 已存储在磁盘上的 CubeSigner 管理会话 (记住,你必须已经登录).

我们还假设,下列进口品可供所有 实例如下.

import * as cs from "@cubist-labs/cubesigner-sdk";
import { JsonFileSessionManager, defaultUserSessionManager } from "@cubist-labs/cubesigner-sdk-fs-storage";
import assert from "assert";

证据 CubeSignerClient

企业的第一顺序是创造一种 CubeSignerClient。 。 。 . 我们只要装上会话符号就可以了 磁盘上的默认位置( 这是 cs login 命令保存 目标:

const cubesigner = await cs.CubeSignerClient.create(defaultUserSessionManager());

或者,a CubeSignerClient 实例可以通过明确 提供会话管理器 :

// Create a session manager backed by a JSON file
const fileStorage = new JsonFileSessionManager(
  `${process.env.HOME}/.config/cubesigner/management-session.json`,
);
await cs.CubeSignerClient.create(fileStorage);

获取 User 财务报告和审定财务报表 Org 资讯

我们现在可以得到一些关于登录用户和 用户属于:

const me = await cubesigner.user();
console.log(me);
assert(me.user_id); // each user has a globally unique ID
assert(me.org_ids); // IDs of all organizations this user is a member of
assert(me.org_ids.length === 1); // assume that the user is a member of exactly one org

const org = await cubesigner.org();
assert(await org.enabled()); // assume that the org is enabled

与一个组织还有许多关系,比如创建/列名 * 键,创建/列入清单,制定全局安全政策, 包括:.

其余的辅导,我们假设登录的用户是一个 至少一个组织的成员.

创建一个 Key

接下来,让我们创建一个钥匙,我们以后会用它来签署伊特鲁姆 交易。 为此,我们需要一种类型的钥匙 Secp256k1.Evm。 。 。 .

const secpKey = await org.createKey(cs.Secp256k1.Evm);
assert((await secpKey.owner()) == me.user_id);
assert(await secpKey.enabled());
assert(await secpKey.type(), cs.Secp256k1.Evm);
console.log(`Created '${cs.Secp256k1.Evm}' key ${secpKey.id}`);

签名 Ethereum 交易

我们做个假人吧 EvmSignRequest。 。 。 .

const eth1Request: cs.EvmSignRequest = {
  chain_id: 1,
  tx: {
    to: "0xff50ed3d0ec03ac01d4c79aad74928bff48a7b2b",
    type: "0x02",
    gas: "0x61a80",
    maxFeePerGas: "0x2540be400",
    maxPriorityFeePerGas: "0x3b9aca00",
    nonce: "0",
    value: "0x100",
  },
};

似乎我们已经准备好一切了 与这个请求签署 键。 但是,试图这样做失败了 403 Forbidden 说些类似的话 Session does not have the required scopes...

try {
  console.log("Trying to sign with improper scopes");
  await secpKey.signEvm(eth1Request);
  assert(false, "Must not be allowed to sign without scopes");
} catch (e) {
  assert(`${e}`.includes("Session does not have required scopes"));
}

默认情况下,CLI创建的会话无法执行签名操作. 所有会议都有一系列 范围 哪个 用于确定该会话的用途。 稍后我们再谈这个 但现在只需要知道 我们需要一个新的会议 有合适的范围:

let signingClient = await cs.CubeSignerClient.create(
  // declare the "sign:*" scope which allows us to sign using any keys the
  // account has access to
  await cubesigner.org().createSession("readme signing demo", ["manage:key:get", "sign:*"]));
const signingKey = new cs.Key(signingClient, secpKey.cached);
let sig = await signingKey.signEvm(eth1Request);
console.log(sig.data());
assert(sig.data().rlp_signed_tx);

使用醚.js而不是直接使用 SDK

如果您的应用程序使用 ethers.js, 您可以配置它来使用 CubeSigner 到 签名交易.

import { Signer } from "@cubist-labs/cubesigner-sdk-ethers-v6";
import { ethers } from "ethers";

// Create new Signer
const ethersSigner = new Signer(secpKey.materialId, signingClient);
assert((await ethersSigner.getAddress()) === ethers.getAddress(secpKey.materialId));
// sign transaction as usual:
console.log(
  "ethers.js signature:",
  await ethersSigner.signTransaction({
    chainId: 1,
    to: "0xff50ed3d0ec03ac01d4c79aad74928bff48a7b2b",
    value: ethers.parseEther("0.0000001"),
  }),
);

访问控制 Role

CubeSigner 在多个用户想要时使用角色来控制密钥的访问 使用它们。 你可以把角色当作团体 允许某些用户访问某些密钥。 要开始,让我们 创建一个 Role 然后直接打电话 createSession 上面写着:

// Create a role, implicitly adding ourselves as a member
const role = await org.createRole();

console.log("Adding key to role, then signing an Ethereum transaction");
await role.addKey(secpKey);

// Members of the role can create sessions which can only access keys in the role
const roleClient = await cs.CubeSignerClient.create(
  // Role sessions implicitly have the "sign:*" scope
  await role.createSession("readme")
);
console.log(`Created client for role '${role.id}'`);

制定安全政策

当我们添加一个 Secp256k1.Evm 关键角色(如上所述),客户端 与这个角色有关,让我们可以签署 任意 以利亚 用那把钥匙进行交易 如果这看起来太宽容, 我们可以附加一个安全 政策限制这一关键要素在这一作用中的允许使用.

例如,将签名限制在事先核准的交易中 接收者,我们可以附加 TxReceiver 我们的关键政策:

console.log("Setting transaction receiver policy");
await secpKey.setPolicy([{ TxReceiver: "0xff50ed3d0ec03ac01d4c79aad74928bff48a7b2b" }]);
console.log("Signing transaction");
const roleKey = new cs.Key(roleClient, secpKey.cached);
sig = await roleKey.signEvm(eth1Request);
assert(sig.data().rlp_signed_tx);

尝试更改交易接收器并验证交易 事实上

console.log("Signing a transaction to a different receiver must be rejected");
try {
  await roleKey.signEvm({
    chain_id: 1,
    tx: {
      ...eth1Request.tx,
      to: "0x0000000000000000000000000000000000000000",
    } satisfies any,
  });
  assert(false, "Must be rejected by policy");
} catch (e) {
  assert(`${e}`.includes("Transaction receiver not allowed by policy"));
}

3⁄4 ̄ ̧漯B 制定新的政策,以覆盖以前的政策。 打电话 Key::appendPolicy 改为 Key::setPolicy 添加到 现有政策.

签个字

这个 CubeSignerClient 班级曝光 signBlob 方法,哪个符号 带有给定密钥的任意( raw, 未解释) 字节包。 这个 但默认不允许操作; 永久 已禁用用于 BLS 键,对于其他键类型,可以通过 附有 "AllowRawBlobSigning" 政策:

// Create a new Ed25519 key (e.g., for Cardano) and add it to our roleClient's role
const edKey = await org.createKey(cs.Ed25519.Cardano);
await role.addKey(edKey);
console.log(`Created '${await edKey.type()}' key ${edKey.id} and added it to role ${role.id}`);

// Sign raw blobs with our new ed key and the secp we created before
for (const key of [edKey, secpKey]) {
  console.log(`Confirming that raw blob with ${await key.type()} is rejected by default`);
  const roleKey = new cs.Key(roleClient, key.cached);
  const blobReq: cs.BlobSignRequest = {
    message_base64: "L1kE9g59xD3fzYQQSR7340BwU9fGrP6EMfIFcyX/YBc=",
  };
  try {
    await roleKey.signBlob(blobReq);
    assert(false, "Must be rejected by policy");
  } catch (e) {
    assert(`${e}`.includes("Raw blob signing not allowed"));
  }

  console.log("Signing raw blob after adding 'AllowRawBlobSigning' policy");
  await key.appendPolicy(["AllowRawBlobSigning"]);
  const blobSig = await roleKey.signBlob(blobReq);
  console.log(blobSig.data());
  assert(blobSig.data().signature);
}

3⁄4 ̄ ̧漯B 当与 a 签下一个生球时 Secp256k1 键,blob 必须 成为SHA-256等安全散列函数的输出,并且必须完全为32字节长. 这是Bitcoin,Ethereum等区块链所使用的ECDSA签名算法的严格要求. 签名任何不是安全散列函数输出的字节字符串,都会导致灾难性的安全故障,包括完全泄露出您的秘密密钥.

试图用分秒键签名无效信件将失败 400 Bad Request 说 Signature scheme: InvalidMessage。 。 。 .

会话管理

在上述例子中,我们使用了三个不同的会议:

  1. 使用 CLI 创建的仅管理范围的用户会话
  2. 我们创建的签名会(1)
  3. 我们创建的角色会议(1)

全体 CubeSignerClients需要有效的会话才能运行。 本节 我们将潜入TypeScript SDK中的会话细节.

从磁盘上装入

如果您已经有一个活动会话在 cs (立方体符号CLI),你可以 用 TypeScript SDK 装入此用户会话如下( 如我们先前所做的) :

await cs.CubeSignerClient.create(defaultUserSessionManager())

或者我们可以使用 CLI 为我们的 JavaScript 客户端创建自己的会话:

cs session create --role-id $ROLE_ID --scope sign-all --output json > session.json

然后我们可以这样装入:

try {
  await cs.CubeSignerClient.create(new JsonFileSessionManager("./session.json"));
} catch {
  console.error("Unable to find file")
}

从内存装入

如果您已经掌握了会话信息SessionData 在内存中,您可以 直接装入客户端.

// Get the session data we want to use with the client
const sessionData: cs.SessionData = await role.createSession("readme");
await cs.CubeSignerClient.create(new cs.MemorySessionManager(sessionData))
// or, for short
await cs.CubeSignerClient.create(sessionData)

[尖叫声]
这样创建的客户端会自动刷新会话 。 如果您尝试与另一个客户端使用此会话, 他们都会尝试刷新, 导致失败 .

管理人员、储存和刷新

正如我们从上面的例子中看到的那样 CubeSignerClients是使用 create 建筑师。 这个 create 构造器接受原始 SessionData 或一个 SessionManager迄今为止,我们已经看到两个不同的会话经理:

  • JsonFileSessionManager
  • MemorySessionManager

这些经理负责保存您的会话符号 并且(可选择地)坚持下去。 当你的会话符号刷新, JsonFileSessionManager 将新符号写入磁盘.

更复杂的管理人员可以通过执行 SessionManager 接口.

为 OIDC 用户创建会话

立方体符号支持 伊办 用于认证第三方用户的标准.

首先,我们需要一个OIDC的标志。 我们可以从Google或其他方面得到一个 支持 OIDC 发行器 ! 为了这个例子,我们假设 oIDC 令牌存储在 OIDC_TOKEN 环境变量

import * as dotenv from "dotenv"; // npm install [email protected]
dotenv.config();

const oidcToken = process.env["OIDC_TOKEN"];
assert(oidcToken);

在使用 OIDC 符号进行认证之前, 我们必须添加 Org 策略 允许特定的发行人/听众对从符号.

const oldOrgPolicy = await org.policy();
const oidcPayload = JSON.parse(atob(oidcToken.split(".")[1].replace(/-/g, "+").replace(/_/g, "/")));
const oidcAuthSourcesPolicy = {
  OidcAuthSources: {
    [oidcPayload.iss]: [oidcPayload.aud],
  },
};
console.log("Setting org policy", oidcAuthSourcesPolicy);
await org.setPolicy([oidcAuthSourcesPolicy]);

最后,将OIDC令牌换成会话.

const oidcSessionResp = await cs.CubeSignerClient.createOidcSession(
  cubesigner.env,
  org.id, // org id to log into
  oidcToken,
  ["manage:mfa:*", "sign:*"] // scopes for the session 
);
const oidcClient = await cs.CubeSignerClient.create(oidcSessionResp.data());

资讯 关于如何使用 SDK 创建 CubeSigner 的全部细节 账户,然后交换有效的 OIDC 令牌 立方体Signer 会话,检查 OIDC 示例。 。 。 .

为用户设置 TOTP

要管理一个用户 我们需要一个与该用户绑定的会话 。 这个 无论该用户是CubeSigner还是第三方的本地人 OIDC用户. 为此,我们将在本节中使用 以前创建的 oidcCubeSigner 举个例子.

为了建立TOTP,我们首先叫 resetTotpStart 启动方法 TOTP重设程序.

console.log(`Setting up TOTP for user ${me.email}`);
let totpResetResp = await oidcClient.resetTotp();

如果用户已经配置了TOTP(或任何其他形式的MFA), 此响应需要多要素认证 。 这样的话, 例如,电话 totpApprove 并提供现有 TOTP 继续:

import { authenticator } from "otplib"; // npm install [email protected]

let totpSecret = process.env["CS_USER_TOTP_SECRET"]!;
if (totpResetResp.requiresMfa()) {
  console.log("Resetting TOTP requires MFA");
  const code = authenticator.generate(totpSecret);
  totpResetResp = await totpResetResp.totpApprove(oidcClient, code);
  assert(!totpResetResp.requiresMfa());
  console.log("MFA approved using existing TOTP");
}

反应包含一个TOTP挑战,即一个新的TOTP 标准形式的配置 TOTP 乌尔。 。 。 . 从该url,我们可以生成一个 QR 代码来呈现给用户,或者 创建自动测试的认证器.

const totpChallenge = totpResetResp.data();
assert(totpChallenge.url);

为了完成挑战,我们必须呼吁 resetTotpComplete 财务报告和审定财务报表 从挑战中提供匹配 TOTP 配置的 TOTP 代码 :

totpSecret = new URL(totpChallenge.totp_url).searchParams.get("secret");
assert(totpSecret);
await totpChallenge.answer(authenticator.generate(totpSecret));

TOTP 配置完成后, 我们可以加倍检查验证器 通过调用生成正确的代码 verifyTotp

console.log(`Verifying current TOTP code`);
let code = authenticator.generate(totpSecret);
await oidcClient.verifyTotp(code);

我们还可以检查用户的配置文件是否确实包括 Totp 作为所配置的外交部因素之一.

const mfa = (await oidcClient.user()).mfa;
console.log("Configured MFA types", mfa);
assert(mfa.map((m) => m.type).includes("totp"));

配置用于签名的外交部政策

我们已经讨论过分配一个 警卫 政策 键; 需要多要素 认证是另一种此类政策.

让我们更新我们 secpKey 键,需要通过 TOTP 在任何可能与该密钥签名之前:

console.log(`Require TOTP for key ${secpKey.materialId}`);
await secpKey.appendPolicy([{ RequireMfa: { count: 1, allowed_mfa_types: ["Totp"] } }]);

现在,当我们呼叫任何签署行动 secpKey,我们会 实收 202 Accepted 改为 200 Ok。反应机构包含 外交部身份证,我们可以用来获取和检查相关的外交部 要求,请看需要多少批准,什么是外交部因素 它允许,等等。 相反,因为我们知道 我们的钥匙需要TOTP,我们 可以打电话 totpApprove 并传递当前 TOTP 代码; 如果代码正确, 调用将会成功 并返回签名.

console.log(`Signing a transaction now requires TOTP`);
const oidcKey = new cs.Key(oidcClient, secpKey.cached);
let resp = await oidcKey.signEvm(eth1Request);
assert(resp.requiresMfa());

console.log(`Approving with TOTP code`);
code = authenticator.generate(totpSecret);
resp = await resp.totpApprove(oidcClient, code);
assert(!resp.requiresMfa());
console.log(resp.data());
assert(resp.data().rlp_signed_tx);

清理

完成后,可以取消签名会话并删除角色 我们创造了.

console.log("Cleaning up");
await signingClient.revokeSession();
await roleClient.revokeSession();
await role.delete();

目前不支持删除密钥 .

建造SDK

npm ci
npm run build

运行 SDK 测试

之后 登录,你可以只运行:

npm test

测试将产生一些临时键和角色(在 组织签名用户,然后签署一些信件,以及 终于清理(大部分)了.

许可证

版权(C)2022-2023 Cubist, Inc.

见 通知 用于许可证信息的文件.

版本与发布记录

@cubist-labs/cubesigner-sdk 共发布 136 个版本,首次发布于 2023/09/08;过去 12 个月发布了 51 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.4.284latest2026/09/092 个月前
0.4.2812026/08/192 个月前
0.4.2802026/08/142 个月前
0.4.2792026/08/122 个月前
0.4.2762026/08/063 个月前
0.4.2752026/08/043 个月前

关于 @cubist-labs/cubesigner-sdk 的常见问题

@cubist-labs/cubesigner-sdk 是什么?

立方体符号类型SDK

如何安装 @cubist-labs/cubesigner-sdk?

在项目目录运行 npm install @cubist-labs/cubesigner-sdk,或使用 pnpm add / yarn add / bun add。

@cubist-labs/cubesigner-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cubist-labs/cubesigner-sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@cubist-labs/cubesigner-sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20.19.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cubist-labs/cubesigner-sdk 可以商用吗?

@cubist-labs/cubesigner-sdk 使用 MIT OR Apache-2.0 许可。可在 MIT、Apache-2.0 中任选其一遵守。选择 MIT 时,宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cubist-labs/cubesigner-sdk 的下载量有多少?

根据 npm 官方下载统计,@cubist-labs/cubesigner-sdk 在 2026/10/11 – 2026/11/09 这 30 天内被下载 19,130 次,日均约 638 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cubist-labs/cubesigner-sdk 还在维护吗?

最新版本 0.4.284 发布于 2026/09/09(2 个月前);至今共发布 136 个版本,其中过去 12 个月发布了 51 个;首次发布于 2023/09/08。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。