buckyos
v0.7.128
Published
BuckyOS WebSDK for browser and Node.js environments
Maintainers
Readme
BuckyOS SDK 与 Tool
buckyos npm 包同时提供 browser/node/provision SDK 和项目本地 CLI。App 开发者只需项目已有的
Node.js,不需要安装 Deno,也不需要 checkout BuckyOS 或本仓库:
npm install buckyos
npx buckyos --version
npx buckyos pikg init . --owner did:bns:alice --kind static-web --source ./dist
npm run build
npx buckyos pikg build ./dapp_meta
npx buckyos pikg pack ./dapp_dist
npx buckyos pikg info ./dapp_dist/example-0.1.0.pikg
npx buckyos app install ./dapp_dist/example-0.1.0.pikg --policy local-developer
npx buckyos task wait <task-id>
npx buckyos app status example
npx buckyos log tail --app example当命令需要读取项目目录和 Tool 包目录之外的源码时,通过可重复的全局参数显式授权:
npx buckyos --allow-read ../shared-assets --allow-read /opt/app-source pikg build ./dapp_meta--allow-read 只增加读权限,不会增加写权限。
npx buckyos 和 npm scripts 中的 buckyos 固定使用项目 lockfile 对应的 Tool。PATH 中裸 buckyos
由 BuckyOS 系统安装器管理并指向 $BUCKYOS_ROOT/bin/buckyos;文档不推荐全局
npm install -g buckyos。两种分发运行同一套命令实现,互不覆盖、互不调用、也不会自更新。
遇到本地构建或目标配置问题,先运行 npx buckyos pikg doctor。--version --verbose 会打印 实际
executable、Node/Deno host、distribution、Tool/SDK/协议版本和本地 policy。
身份验证
然后在浏览器中允许的,属于dApp的页面,都应使用BuckyOS SDK提供的登陆功能来获得一个有效身份。 身份验证流程如下:
路径1:1.浏览器发送请求 --HTTPs--> 2.cyfs-gateway进行验证 --Local HTTP--> 3.dApp Server使用BuckyOS Rust SDK进行验证。 路径2:1. App -->http@bdt--> 2.cyfs-gateway进行验证 -- Local HTTP--> 3.dApp Server使用BuckyOS Rust SDK进行验证。 路径2 依赖有客户端身份的App/CYFS 浏览器,暂未实现 路径3:1.App Service --RPC@http--> 2. system_service(验证rpc.token,系统调用验证,不走cyfs-gateway)
cyfs-gateway的验证
cyfs-gateway会根据HTTP Request的Host字段和cookie中的buckyos_token字段来进行验证。 该buckyos_token通常是有相对较长有效期的普通权限jwt. 对POST请求,验证首先要得到jwt格式的rpc.token,然后进一步验证该rpc请求是否有正确的授权。涉及到敏感操作的rpc.jwt通常是短期的,甚至是一次性的,并有sudo级别权限。
验证方根据buckyos_token / rpc_token得到appid,userid,resource,OP组成四元组,到RBAC库中查询对应权限,并进行验证。 RBCL需要的四元组:
appid,来自http request的host字段,web sdk里不可设置
userid:必填
resource:来自http request的path字段.完整写法是app://appid/http_path/,各种系统调用都有自己构造path的方法,与参数有关。jwt中通常不包resource信息,除非特别敏感的一次性sudo操作
OP: 来自http request的method字段 (GET/POST/PUT/DELETE/...),jwt中是可以包含的。cyfs-gateway会根据这四元组,到RBAC库中查询对应权限,并进行验证。其验证方法是先判断appid是否有权限,再判断userid是否有权限。任何一个不通过,都会返回权限不足。
cyfs-gateway对于需要http验证的请求,如果没有buckyos_token字段,会重定向到一个预设的访问登陆页,引导用户登陆成功后,再重定向回原URL。该登陆页面通常是支持guest访问的。
buckyos_token字段的生成
// at feedlist.excample.com
await buckyos.loginByBrowserSSO()
// 当前窗口会跳转到 sys.$zoneid/sso/login
// SSO 成功并跳回当前页后,再读取当前账号状态
let user_info = await buckyos.getAccountInfo()
let bucky_token = user_info?.session_token
let user_id = user_info?.user_id
let rpc_client = new buckyos.kRPCClient(feedlist_api_url, bucky_token)
let user_feeds = rpc_client.get_user_feeds(user_id)执行高权限操作
on_click_change_password(){
let new_password = get_new_password();
let bucky_token =await buckyos.authClient.request("change password");
let rpc_client = new buckyos.kRPCClient(account_api_url,bucky_token);
//高权限操作的所有参数都在bucky_token的payload中
rpc_client.change_password(bucky_token);
}下面是feedlist_api的实现
on_request(request,response){
let user_id = request.params.user_id
let token = request.bucky_token;
payload = verify_token(token,verify_hub.public_key);
if payload.userid != user_id {
response.send(403,"permission denied");
}
if payload.appid != "feedlist" {
response.send(403,"permission denied");
}
response.send(user_feeds);
}buckyos.authClient的实现
authClient主要靠系统的内置verify_hub服务来完成功能,其基本逻辑是
- 在当前窗口直接跳转到标准的
sys.$zoneid/sso/login页面,该页面会根据 login 时的参数调整一些行为 - 用户在跳转后的页面中完成登录,有2种方法 a. 使用用户名密码向verify_hub发起请求,verify_hub会根据其掌握的账号信息返回必要的jwt验证信息 b. 要求用户输入一个加密后的私钥,当用户输入正确的解密密码后,可以用该私钥来构造jwt
bucky_token jwt payload的内容
签名都是verify_hub服务完成的
{
"appid": "$appid",
"userid": "$did",
"key":"$aes_key", 用verify_hub的公钥加密的aes key,也用来做session key
"iss": "verify_hub", 或 "$did",使用用户的私钥来构造jwt时,会使用用户的sudo权限
"exp": "$exp"
}防御jwt的重放攻击
因为会工作在http环境,因此会用明文发送jwt.
namelib 与 provision(身份文档构造)
SDK 自带 Rust name-lib 的 TS 镜像(namelib,universal 导出),以及 buckycli 构造侧命令的 TS
镜像(buckyos/provision,node-only,要求 Node >= 22.13 或 Deno >= 2.2,依赖
node:sqlite)。格式与 Rust 端逐字节对齐 (Ed25519 PKCS8 PEM / JWK / EdDSA JWT),由 golden fixture
单测保障 (tests/fixtures/provision/)。
Quickstart:keygen → createUserEnv → createNodeConfigs
import { namelib } from 'buckyos'
import { createNodeConfigs, createSnConfigs, createUserEnv } from 'buckyos/provision'
// 1. 生成 Ed25519 身份密钥(私钥 PKCS8 PEM + 公钥 JWK)
const { privateKeyPem, publicKeyJwk } = await namelib.generateEd25519KeyPair()
// 2. 构造用户/zone 环境(user_config.json、zone_config.json、zone TXT record 等)
await createUserEnv({
username: 'alice',
hostname: 'alice.bns.did',
oodName: 'ood1',
snBaseHost: 'devtests.org',
outputDir: '/tmp/alice-env',
})
// 3. 构造节点身份(node_identity.json、device_mini_config.jwt、start_config.json)
await createNodeConfigs({ deviceName: 'ood1', envDir: '/tmp/alice-env' })其它能力:createSnConfigs / registerUserToSn / registerDeviceToSn(SN 侧)、 setPkgMeta /
MetaIndexDb(pkg meta 索引库)、buildDidDocs(内核服务 did docs)、 createCa /
createCertFromCa(旧 CertManager 兼容 TLS 证书),以及 IdentityRoots /
createIdentityCertFromCa(按 identity path 协议写入
$BUCKYOS_IDENTITY_ROOT/{encoded raw host URI}/server.* 和
$BUCKYOS_SECURITY_ROOT/{encoded raw host URI}/server.private.pem;现阶段不生成
server.keyref.json)。
注意:buckyos/provision 导出的 DEV_TEST_KEYS / dev EVM account helper 是仅供本地开发
的公开测试密钥,使用固定 dev 助记词按 Rust name-lib 的 mnemonic 派生规则构造,严禁用于
真实激活流程;浏览器 bundle 不包含 provision。
构建与发布
本地构建
构建项目并生成类型定义文件:
# 使用 pnpm(推荐)
pnpm run build:all
# 或使用 npm
npm run build:all该命令会执行以下操作:
- 运行
vite build构建项目,生成dist/index.*、dist/browser.*、dist/node.* - 运行
tsc -p tsconfig.build.json生成对应的 TypeScript 类型定义文件 - 生成与 package version 一致的 Tool 版本文件,并构建 Node CLI bundle
构建产物位于 dist/ 目录。
AppClient Demo
仓库里带了一个最小可运行的 AppClient 示例:examples/app_client_demo.ts。
它会:
- 使用本机私钥目录初始化
AppClient - 向真实运行中的
system_config读取boot/config - 打印当前
session_token的 claims 和boot/config的顶层 key
运行方式:
pnpm run demo:app-client可选环境变量:
BUCKYOS_TEST_APP_ID=buckycli
BUCKYOS_SYSTEM_CONFIG_URL=http://127.0.0.1:3200/kapi/system_config如果你是在已发布的 SDK 包里使用,同样的示例代码应从 buckyos/node 导入,而不是仓库内的相对路径。
发布到 GitHub
1. 更新版本号
在 package.json 中更新版本号:
# 使用 npm version 自动更新版本号并创建 git tag
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.0 -> 1.1.0
npm version major # 1.0.0 -> 2.0.02. 构建项目
确保构建产物是最新的:
pnpm run build:all3. 提交并推送
# 提交更改
git add .
git commit -m "chore: release v1.0.1"
# 推送代码和标签到 GitHub
git push
git push --tags4. 创建 GitHub Release(可选)
- 访问 GitHub 仓库页面
- 点击 "Releases" -> "Create a new release"
- 选择刚才推送的 tag
- 填写 Release 标题和描述
- 上传构建产物(
dist/目录下的文件)作为附件(可选)
发布到 npm
发布工作流使用 npm Trusted Publishing/provenance、最小权限和 npm 账号 2FA。首次包含 Tool 的
版本只能进入 next/beta,不得直接覆盖 latest:
pnpm run build
pnpm run check:cli
pnpm run test:cli
pnpm run test:cli-conformance
pnpm run test:tarball
pnpm run test:release-manifest
npm publish --tag next --provenance系统打包必须固定这次 CI 生成的原始 npm tarball、CycloneDX SBOM、release manifest 和 Deno digest,不得重新 checkout 或重建。真实 App/DV、系统离线安装、升级和回滚验收通过后,只移动 dist-tag:
npm dist-tag add buckyos@<已验证版本> latest回滚 dist-tag 不会改变已经安装的 BuckyOS system Tool;系统 Tool 只随 installer/updater 事务 更新或回滚。
Session inbox addresses (breaking change)
MsgCenter queue calls (getNext, peekBox, listBoxByTime) require mailbox
in place of owner: did:bns:alice/session-123 selects exactly that session;
did:bns:alice selects only records without a session. Existing session_id
values define the partitions, including automatically derived dm:<peer DID>
and group sessions. Set msg.to_session (MsgObject v2) to address a chosen session;
msg.thread.topic is only a semantic hint and never selects a session.
import { mailboxAddress } from 'buckyos'
const record = await client.getNext({
mailbox: mailboxAddress('did:bns:alice', 'session-123'),
box_kind: 'INBOX',
lock_on_take: true,
})listMailboxes(owner, boxKind) lists inboxes with unread records for an authorized
owner-wide router. moveRecord(recordId, mailbox) moves a record within one
owner; updateRecordSession also moves its inbox. Both source and destination
require write access. Omitting the session in moveRecord selects the default
inbox. Record responses include their canonical mailbox address.
RBAC resources are obj://msg-center/inbox/<did>/<session_id> (and analogous
sent, group_inbox, request_box paths). Read access permits non-locking
reads; consumption and updates require write access. Exact grants do not cover
other sessions, the default inbox, owner-wide projections, or delivery queues.
Use mailboxResource(mailboxAddress(owner, sessionId), 'INBOX') to construct
RBAC policy keys. Resource encoding additionally escapes dots, percent signs,
and pattern characters so keyMatch3 cannot expand an exact session grant.
For example, did:web:agent.zone/approval.1 maps to
obj://msg-center/inbox/did:web:agent%2Ezone/approval%2E1.
