@ atcute/ identity- solover
操作和完成 AT 协议的文档解析.
npm install @atcute/identity-resolver
在AT 协议中,控件(如 alice.bsky.social需要解决DCDs, 而DIDs需要
解析为 DID 文档(其中包含用户的PDS位置和密钥). 此软件包提供了
双方的解决方案.
使用量
解析手柄
手柄可以通过 DNS TXT 记录或 HTTP 知名端点来解决. 使用复合解析器 尝试两种:
import {
CompositeHandleResolver,
DohJsonHandleResolver,
WellKnownHandleResolver,
} from '@atcute/identity-resolver';
const handleResolver = new CompositeHandleResolver({
methods: {
dns: new DohJsonHandleResolver({ dohUrl: 'https://mozilla.cloudflare-dns.com/dns-query' }),
http: new WellKnownHandleResolver(),
},
});
const did = await handleResolver.resolve('bsky.app');
// -> "did:plc:z72i7hdynmk6r22z27h6tvur"
决议战略
复合解析器支持结合 DNS 和 HTTP 分辨率的不同策略 :
const handleResolver = new CompositeHandleResolver({
strategy: 'race', // default - first successful response wins
methods: { dns: dnsResolver, http: httpResolver },
});
现有战略:
race- 返回首先成功的方法(默认)dns-first- 先试试DNS,如果失败就回HTTPhttp-first-先试试HTTP,如果失败就回DNSboth- 要求两种方法都同意(投掷)AmbiguousHandleError如果两者不同)
解析已执行的文档
DID 文档可以解析为 id:plc 和 did:web 方法 :
import {
CompositeDidDocumentResolver,
PlcDidDocumentResolver,
WebDidDocumentResolver,
} from '@atcute/identity-resolver';
const didResolver = new CompositeDidDocumentResolver({
methods: {
plc: new PlcDidDocumentResolver(),
web: new WebDidDocumentResolver(),
},
});
const doc = await didResolver.resolve('did:plc:z72i7hdynmk6r22z27h6tvur');
// -> { '@context': [...], id: 'did:plc:...', service: [...], ... }
解决行为者
页:1 ActorResolver 界面提供了一种方法,可以解决一个角色标识符(处理或DID)到
需要与它们进行互动的重要信息:它们已经实现的、经过核实的手柄和PDS的终点.
LocalActorResolver 通过将控件和文档解析合并到本地来实现 :
import { LocalActorResolver } from '@atcute/identity-resolver';
const actorResolver = new LocalActorResolver({
handleResolver,
didDocumentResolver: didResolver,
});
// resolve from handle
const actor = await actorResolver.resolve('bsky.app');
// -> { did: "did:plc:...", handle: "bsky.app", pds: "https://..." }
// resolve from DID
const actor2 = await actorResolver.resolve('did:plc:z72i7hdynmk6r22z27h6tvur');
// -> { did: "did:plc:...", handle: "bsky.app", pds: "https://..." }
本地解析器执行双向验证: 它检查 DID 中的控点 文档解析为相同的已执行 .
其他执行 ActorResolver 可从专用身份服务处获得此信息( 如
Slingshot),无需取取并解析完整DD文件.
处理出错
每个解析器为不同的失败大小写丢出特定错误类型 :
import {
DidNotFoundError,
InvalidResolvedHandleError,
AmbiguousHandleError,
FailedHandleResolutionError,
HandleResolutionError,
} from '@atcute/identity-resolver';
try {
const did = await handleResolver.resolve('nonexistent.invalid');
} catch (err) {
if (err instanceof DidNotFoundError) {
// handle has no DID record
console.log('handle not found');
} else if (err instanceof InvalidResolvedHandleError) {
// handle returned an invalid DID format
console.log('invalid DID:', err.did);
} else if (err instanceof AmbiguousHandleError) {
// multiple different DIDs found (with 'both' strategy)
console.log('ambiguous handle');
} else if (err instanceof FailedHandleResolutionError) {
// network or other unexpected error
console.log('resolution failed:', err.cause);
} else if (err instanceof HandleResolutionError) {
// catch-all for any handle resolution error
}
}
文件解析错误 :
import {
DocumentNotFoundError,
UnsupportedDidMethodError,
ImproperDidError,
FailedDocumentResolutionError,
DidDocumentResolutionError,
} from '@atcute/identity-resolver';
try {
const doc = await didResolver.resolve('did:example:123');
} catch (err) {
if (err instanceof DocumentNotFoundError) {
// DID document doesn't exist
} else if (err instanceof UnsupportedDidMethodError) {
// resolver doesn't support this DID method
} else if (err instanceof ImproperDidError) {
// DID format is invalid for this method
} else if (err instanceof FailedDocumentResolutionError) {
// network or other unexpected error
} else if (err instanceof DidDocumentResolutionError) {
// catch-all for any DID resolution error
}
}
缓存和中止信号
所有解析器接受缓存控制和取消的选项 :
// skip cache
const did = await handleResolver.resolve('bsky.app', { noCache: true });
// with abort signal
const controller = new AbortController();
const did = await handleResolver.resolve('bsky.app', { signal: controller.signal });
// cancel the request
controller.abort();
自定义抓取函数
所有解析器接受自定义获取执行 :
const dnsResolver = new DohJsonHandleResolver({
dohUrl: 'https://mozilla.cloudflare-dns.com/dns-query',
fetch: customFetch,
});
const httpResolver = new WellKnownHandleResolver({
fetch: customFetch,
});
const plcResolver = new PlcDidDocumentResolver({
fetch: customFetch,
});
服务器侧分辨率和 SSRF
解决服务器上的不可信身份可以将内部服务暴露给服务器侧请求
伪造(SSRF). 例如, did:web:localhost%3a6379 瞄准HTTP上的回回地址
did:web:169.254.169.254 目标为链接本地地址.
解析器不限制目标 IP。通过自定义 fetch 拒绝非公众
连接时的地址。 仅检查主机名是不够的: DNS 可以解决公众
私人IP的主机名 .
const didResolver = new CompositeDidDocumentResolver({
methods: {
plc: new PlcDidDocumentResolver({ fetch: safeFetch }),
web: new WebDidDocumentResolver({ fetch: safeFetch }),
},
});
关于云旗工人,启用 global_fetch_strictly_public 在朗格勒配置。 打开
节点.js,使用一个获取调度器,在连接时间检查目的地IP.
自定义 PLC 目录
默认情况下, 是否使用: plc 解析度 https://plc.directory。您可以指定不同的目录 :
const plcResolver = new PlcDidDocumentResolver({
apiUrl: 'https://plc.wtf', // mirror of plc.directory
});
解析器类
处理解析器
| 类 | 说明 |
|---|---|
DohJsonHandleResolver | 通过 DNS- over- HTTPS (TXT 记录于 _atproto.{handle}(中文(简体) ) |
WellKnownHandleResolver | 通过 HTTP 解析( L)https://{handle}/.well-known/atproto-did(中文(简体) ) |
XrpcHandleResolver | 通过 XRPC 解决(com.atproto.identity.resolveHandle(中文(简体) ) |
CompositeHandleResolver | 结合 DNS 和 HTTP 解析器 |
D. 文档解析器
| 类 | 说明 |
|---|---|
PlcDidDocumentResolver | 解析已实现: plc 从 PLC 目录 |
WebDidDocumentResolver | 解析已实现: 来自域名的web |
XrpcDidDocumentResolver | 通过 XRPC 解决(com.atproto.identity.resolveDid(中文(简体) ) |
CompositeDidDocumentResolver | 通过 DOD 方法解析器的路径 |
演员解析器
| 类 | 说明 |
|---|---|
LocalActorResolver | 将处理和DD 解析与双向核查相结合 |