概览
在即将发布的 Blocklet Server v1.17.x 版本中,我们对 Blocklet Server 的一系列安全场景进行了优化,但同时也带来了一些 Breaking Change:
- 删除了 Blocklet 的部分环境变量(
BLOCKLET_APP_SK、BLOCKLET_APP_PSK)。 - @blocklet/sdk 的
getWallet()返回对象删除了wallet.secretKey/wallet.sk属性; - @blocklet/sdk 和 @ocap/wallet 的签名/验证函数多数从同步改为异步。
- 多个包的导出方式从 CommonJS 默认导出变为 ES Module 的命名导出。
- 以下场景的签名/验证私钥由原来的 BLOCKLET_APP_SK 变更为 BLOCKLET_APP_ASK:跨 Component 调用 / 调用 Service API / Server API / Notification 或 WebSocket
- 增加了部分环境变量:
- BLOCKLET_APP_ASK: 新环境变量,用来以下场景签名:跨 Component 调用 / 调用 Service API / Server API / Notification 或 WebSocket
- BLOCKLET_APP_PPK:为原来
BLOCKLET_APP_PSK的公钥
本指南把这些改动拆解成明确的迁移步骤、替换示例、以及回归检查项,方便逐步修改与人工复核。
在修改之前,请确保所有相关依赖已升级至最新版本(版本为 1.17.1)。
此文档可复制给 AI,由 AI 进行迁移和修改。
主要 Breaking Changes 列表
1. 环境变量变动
变更:BLOCKLET_APP_SK、BLOCKLET_APP_PSK 已删除。任何依赖这些私钥的代码必须改为通过 @blocklet/sdk 的 wallet 接口签名或导出公钥用于校验。
迁移要点:
- 如果代码直接使用私钥进行签名 -> 改为 getWallet() 获取 wallet 并使用其异步签名方法(参见示例)。
- 如果用私钥派生子钱包 -> 使用 await getWallet().deriveWallet()
- 如果只用于 verify -> 使用公钥 getWallet().publicKey 或 process.env.BLOCKLET_APP_PK 来替换。
SK 签名:
旧代码:
const wallet = fromSecretKey(process.env.BLOCKLET_APP_SK);
const signature = wallet.sign();新代码:
const { getWallet } = require('@blocklet/sdk/lib/wallet');
const wallet = await getWallet();
const signature = await wallet.sign();JWT 签名:
旧:
const jwtToken = jwt.sign(payload, process.env.BLOCKLET_APP_SK);新:
const { getWallet } = require('@blocklet/sdk/lib/wallet');
const wallet = await getWallet();
const jwtToken = await wallet.signJWT(payload);SK 验证:
旧:
const wallet = fromSecretKey(process.env.BLOCKLET_APP_SK);
const isValid = wallet.verify(data);新:
const wallet = fromSecretKey(process.env.BLOCKLET_APP_PK);
const isValid = wallet.verify(data);fromAppDid:
旧:
// BLOCKLET_APP_SK
const wallet = fromAppDid(address, process.env.BLOCKLET_APP_SK, { role: types.RoleType.ROLE_ACCOUNT }, x)
// BLOCKLET_APP_PSK
const wallet = fromAppDid(address, process.env.BLOCKLET_APP_PSK, { role: types.RoleType.ROLE_ACCOUNT }, x)新:
const { deriveWallet } = require('@blocklet/sdk/lib/wallet');
// BLOCKLET_APP_SK
const wallet = await deriveWallet(address, { role: types.RoleType.ROLE_ACCOUNT }, x);
// BLOCKLET_APP_PSK
const wallet = await deriveWallet(address, { role: types.RoleType.ROLE_ACCOUNT }, x, 'psk');2. getWallet() 返回对象的改动
变更:删除 wallet.secretKey / wallet.sk 等属性;签名/验证方法均改为异步。
迁移要点:
- 所有 wallet.sign()、wallet.verify() 等调用必须 await。
- 若代码依赖 wallet.secretKey 进行签名或派生,请参考 1. 环境变量变动 的改动。
示例:
旧:
const { getWallet } = require('@blocklet/sdk/lib/wallet');
const wallet = getWallet();
const sig = wallet.sign(data);
console.log(wallet.secretKey) // sk....新:
const { getWallet } = require('@blocklet/sdk/lib/wallet');
const wallet = await getWallet();
const sig = await wallet.sign(data);
console.log(wallet.secretKey) // undefined3. 多个导出变为命名(ESM)导出
变更:一些包从默认导出或 CommonJS 风格改为命名导出。导入语法需调整。
常见替换模式:
- import parse from '@blocklet/meta/lib/parse';
+ import { parse } from '@blocklet/meta/lib/parse';
- const env = require('@blocklet/sdk/lib/env');
+ const { env } = require('@blocklet/sdk/lib/env');受影响的包与常见导出(请在代码库中全局搜索并替换):
- @blocklet/sdk:
BlockletAuthenticator,createConnectHandlers,Database,authMiddleware,fallback,sessionMiddleware,sitemap,userMiddleware,WalletAuthenticator,WalletHandlers,getWallet,getPkWallet,createRemoteWallet,deriveWallet,getPermanentWallet,getEthereumWallet,getAccessWallet,env,BlockletService等。 - @blocklet/meta:
toBlockletDid,validateBlockletEntry,getComponentProcessId,hasReservedKey,getBlockletInfo,parseNavigation,parse,urlPathFriendly,verifyMultiSig,getApplicationWallet,checkBlockletEnvironment,env。 - @blocklet/env:以前直接默认导出 env,现在需要从 blockletEnv / env 命名导出中解构。
建议使用 IDE 的全仓 grep/replace 或逐文件修改,确保引入方式与导出的命名保持一致。
4. 同步 -> 异步:需要在调用处添加 await 与 async
变更:下列函数/方法现在为异步(仅列出高频用到的)。请将调用处添加 await,并将包含调用的函数标注为 async。
4.1 @blocklet/sdk
verify() / sign() / getSignData()(lib/util/verify-sign.ts)signResponse() / verifyResponse()(lib/security)getDelegation()(lib/connect/shared.ts)verifyBlockletSig()(lib/middlewares/blocklet.ts)subscribe() / unsubscribe()(lib/service/eventbus.ts)ensureClient() / on()(lib/service/notification.ts)
4.2 @ocap/wallet
由库生成的 wallet 实例(或 getWallet() 返回)的方法均改为异步:
wallet.sign()wallet.verify()wallet.ethSign()wallet.ethVerify()
4.3 其他库(常见)
- @arcblock/jwt:
jwt.sign(),jwt.verify(),jwt.signV2()-> await。 - @blocklet/meta:
signResponse(),verifyResponse()-> await。 - @asset/vc:
create(),verify(),verifyPresentation(),createCredentialList(),verifyCredentialList()-> await。 - @blocklet/js-sdk:
verifyResponse()-> await。 - @blocklet/store / @blocklet/cli:
sign()-> await。 - @blocklet/server-js:
_getAuthHeaders(),getAuthHeaders(),signWithAccessKey()-> await。
5. 签名与调用场景的特殊说明(关键)
以下场景(跨 Component 调用 / 调用 Service API / Notification 或 WebSocket),签名私钥用原来的 process.env.BLOCKLET_APP_SK,改成 access wallet 的 secretKey。
迁移要点:
- 使用 @blocklet/sdk 的
getAccessWallet()获取 access wallet(包含签名密钥),并将 secretKey 显式传入 sign() / verify() / getSignData() 的 options。示例:
import { sign, verify, getSignData } from '@blocklet/sdk/lib/util/verify-sign';
import { getAccessWallet } from '@blocklet/sdk/lib/wallet';
const accessWallet = await getAccessWallet();
// sign
const result = await axios({
url: '/service/api',
data: json,
headers: {
'x-app-id': accessWallet.address,
'x-app-pk': accessWallet.publicKey,
'x-component-sig': await sign(json, { appSk: accessWallet.secretKey }),
'x-component-did': process.env.BLOCKLET_COMPONENT_DID
},
});
// verify
const isValid = await verify(data, signature, { appSk: accessWallet.secretKey });
// getSignData
const signData = await getSignData(data, { appSk: accessWallet.secretKey });代码迁移清单(按优先级)
- 在代码库根目录运行升级命令并安装依赖。创建单独分支。
- 全仓搜索并替换导入方式(CommonJS 默认导出 -> 命名导出)。
- 全仓搜索 getWallet() / fromSecretKey() / fromAppDid() 等用法:
- 用到私钥属性(secretKey / sk)的位置需替换为 getWallet() 签名或 getAccessWallet() 并使用 appSk。
- 将所有 sign() / verify() / getSignData() 等变更为 await。
- 针对跨组件/Service/Notification/WebSocket 的调用,确保使用 getAccessWallet() 并把 appSk 传给签名方法。
- 修改后运行 TypeScript/Node 构建及单元/集成测试,捕获遗漏的同步调用或导入错误。
- 逐文件人工复核:特别关注在中间件、service、eventbus、notification、connect 相关的代码路径。
常见问题与排错建议
- Bad secret key size
- 原因:未将依赖升级到最新版本
- 各种 verify 失败
- 确认签名使用的是 access wallet 的 secretKey
- 其他组件启动失败
- 请将你应用中的所有组件都升级到最新版,彻底停止后,再启动