# @cubist-labs/cubesigner-sdk 中文文档

规范地址：https://npmcn.com/package/%40cubist-labs/cubesigner-sdk/

版本：0\.4\.284
npm 元数据更新时间：2026-09-09T06:43:20.541Z
中文译文更新时间：2026-11-11T04:19:26.306Z
软件包许可：MIT OR Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cubist-labs/cubesigner-sdk
原文对照：https://npmcn.com/package/%40cubist-labs/cubesigner-sdk/?lang=original
项目主页：https://github.com/cubist-labs/CubeSigner-TypeScript-SDK#readme
源码仓库：https://github.com/cubist-labs/CubeSigner-TypeScript-SDK

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：8.5 MB，245 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20\.19\.0
- 运行依赖：2 个
- 首次发布：2023-09-07T16:47:00.730Z
- 最新版本发布：2026-09-09T06:43:20.210Z
- 近 30 天下载量：19130（2026-10-11 至 2026-11-09，npm 官方下载统计）
- 已发布版本数：136（近 12 个月 51 个）

## 中文简介

立方体符号类型SDK

## 安装

```sh
npm install @cubist-labs/cubesigner-sdk
```

也可以使用：`pnpm add @cubist-labs/cubesigner-sdk`、`yarn add @cubist-labs/cubesigner-sdk`、`bun add @cubist-labs/cubesigner-sdk`

## README

# 立方体符号类型SDK

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

## 立方体符号背景

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

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

## 安装 SDK

您可以从 npm 安装 SDK :

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

## 登录到立方体符号

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

```bash
cs login owner@example.com --env '<gamma|prod|...>'
```

## 开始

> \[TIP\] 用于从 `v0.3.*` 改为 `v0.4.*`请看 [移民.md](https://npmcn.com/MIGRATION.md#v03-to-v04)

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

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

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

```typescript
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` 命令保存 目标:

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

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

```typescript
// 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` 资讯

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

```typescript
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`。 。 。 .

```typescript
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`。 。 。 .

```typescript
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...`

```typescript
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创建的会话无法执行签名操作. 所有会议都有一系列 _范围_ 哪个 用于确定该会话的用途。 稍后我们再谈这个 但现在只需要知道 我们需要一个新的会议 有合适的范围:

```typescript
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 到 签名交易.

```typescript
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` 上面写着:

```typescript
// 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` 我们的关键政策:

```typescript
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);
```

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

```typescript
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"` 政策:

```typescript
// 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)

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

### 从磁盘上装入

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

```typescript
await cs.CubeSignerClient.create(defaultUserSessionManager())
```

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

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

然后我们可以这样装入:

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

### 从内存装入

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

```typescript
// 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)
```

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

### 管理人员、储存和刷新

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

-   `JsonFileSessionManager`
-   `MemorySessionManager`

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

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

### 为 OIDC 用户创建会话

立方体符号支持 [伊办](https://openid.net/developers/how-connect-works/) 用于认证第三方用户的标准.

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

```typescript
import * as dotenv from "dotenv"; // npm install dotenv@16.3.1
dotenv.config();

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

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

```typescript
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令牌换成会话.

```typescript
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 示例](https://npmcn.com/examples/oidc/README.md)。 。 。 .

### 为用户设置 TOTP

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

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

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

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

```typescript
import { authenticator } from "otplib"; // npm install otplib@12.0.1

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 乌尔](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)。 。 。 . 从该url,我们可以生成一个 QR 代码来呈现给用户,或者 创建自动测试的认证器.

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

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

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

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

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

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

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

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

我们已经讨论过分配一个 [警卫 政策](https://npmcn.com/package/%40cubist-labs/cubesigner-sdk/#readme-set-security-policies) 键; 需要多要素 认证是另一种此类政策.

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

```typescript
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 代码; 如果代码正确, 调用将会成功 并返回签名.

```typescript
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);
```

### 清理

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

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

目前不支持删除密钥 .

## 建造SDK

```bash
npm ci
npm run build
```

## 运行 SDK 测试

之后 [登录](https://npmcn.com/package/%40cubist-labs/cubesigner-sdk/#readme-logging-into-cubesigner),你可以只运行:

```bash
npm test
```

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

## 许可证

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

见 [通知](https://npmcn.com/NOTICE) 用于许可证信息的文件.

## 常见问题

### @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 和提交记录判断。

