@agentunion/fastaun 0.5.26 → 0.5.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/_packed_docs/CHANGELOG.md +77 -0
- package/_packed_docs/INDEX.md +37 -14
- package/_packed_docs/KITE_DOCS_GUIDE.md +23 -15
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +16 -1
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +37 -9
- package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +20 -9
- package/_packed_docs/cli/CLI/346/211/213/345/206/214.md +57 -12
- package/_packed_docs/sdk/0.5.22-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +2 -2
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +2 -2
- package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +187 -73
- package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +1 -1
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +13 -9
- package/_packed_docs/sdk/INDEX.md +23 -13
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +973 -266
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +950 -242
- package/dist/agent-md-changes.d.ts +42 -0
- package/dist/agent-md-changes.js +339 -0
- package/dist/agent-md-changes.js.map +1 -0
- package/dist/agent-md-schema.d.ts +1 -0
- package/dist/agent-md-schema.js +31 -14
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +11 -0
- package/dist/agent-md.js +91 -15
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +11 -0
- package/dist/aid-store.js +102 -21
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.js +3 -3
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts +10 -0
- package/dist/auth.js +65 -23
- package/dist/auth.js.map +1 -1
- package/dist/cert-utils.d.ts +1 -1
- package/dist/cert-utils.js +4 -4
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/control-messages.d.ts +31 -0
- package/dist/client/control-messages.js +474 -0
- package/dist/client/control-messages.js.map +1 -0
- package/dist/client/delivery.js +10 -2
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/lifecycle.d.ts +1 -1
- package/dist/client/lifecycle.js +10 -0
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.js +84 -14
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +3 -0
- package/dist/client/v2-e2ee.js +12 -0
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +38 -0
- package/dist/client.js +572 -36
- package/dist/client.js.map +1 -1
- package/dist/discovery.d.ts +3 -0
- package/dist/discovery.js +52 -2
- package/dist/discovery.js.map +1 -1
- package/dist/events.js +14 -1
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts +38 -0
- package/dist/facades.js +49 -5
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/org-protocol.d.ts +1 -0
- package/dist/org-protocol.js +39 -36
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.js +7 -7
- package/dist/ownership-v21.js.map +1 -1
- package/dist/register-flow.js +2 -2
- package/dist/register-flow.js.map +1 -1
- package/dist/risk-control.d.ts +68 -0
- package/dist/risk-control.js +344 -0
- package/dist/risk-control.js.map +1 -0
- package/dist/semantic-facade.d.ts +176 -0
- package/dist/semantic-facade.js +611 -0
- package/dist/semantic-facade.js.map +1 -0
- package/dist/semantic-protocol.d.ts +810 -0
- package/dist/semantic-protocol.js +894 -0
- package/dist/semantic-protocol.js.map +1 -0
- package/dist/storage/lowlevel.d.ts +1 -0
- package/dist/storage/lowlevel.js +2 -2
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +11 -1
- package/dist/tools/cross-sdk-agent.js +388 -7
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +22 -1
- package/dist/transport.js +227 -22
- package/dist/transport.js.map +1 -1
- package/dist/v2/e2ee/decrypt.d.ts +5 -0
- package/dist/v2/e2ee/decrypt.js +22 -2
- package/dist/v2/e2ee/decrypt.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/auth.d.ts
CHANGED
|
@@ -48,6 +48,14 @@ export declare class AuthFlow {
|
|
|
48
48
|
private _gatewayCaVerified;
|
|
49
49
|
private _memIdentity;
|
|
50
50
|
private _identityPkiContext;
|
|
51
|
+
private _requestAdmission;
|
|
52
|
+
private _riskCapabilityEnabled;
|
|
53
|
+
private _httpHandler;
|
|
54
|
+
setRequestAdmission(admission: ((request: string) => () => void) | null): void;
|
|
55
|
+
setRiskSupport(enabled: () => boolean): void;
|
|
56
|
+
setHttpHandler(handler: (url: string, init: RequestInit, perform: (url: string, init: RequestInit) => Promise<Response>) => Promise<Response>): void;
|
|
57
|
+
_fetchRiskText(url: string): Promise<string>;
|
|
58
|
+
private _fetchRiskJson;
|
|
51
59
|
constructor(opts: {
|
|
52
60
|
tokenStore: TokenStore;
|
|
53
61
|
crypto: CryptoProvider;
|
|
@@ -130,6 +138,7 @@ export declare class AuthFlow {
|
|
|
130
138
|
resolveOwnershipCertificate(gatewayUrl: string, aid: string, fingerprint: string, purpose?: 'signing' | 'group_identity'): Promise<OwnershipCertificate>;
|
|
131
139
|
private _verifyOwnershipCertificate;
|
|
132
140
|
private _fetchOwnershipPki;
|
|
141
|
+
private _fetchOwnershipPkiDirect;
|
|
133
142
|
/** 预置 Gateway CA 链材料,但不标记为已验证。 */
|
|
134
143
|
cacheGatewayCaChain(gatewayUrl: string, caChainPems: string[], chainAid?: string): void;
|
|
135
144
|
/** 丢弃预置或缓存的 Gateway CA 链材料。 */
|
|
@@ -139,6 +148,7 @@ export declare class AuthFlow {
|
|
|
139
148
|
* 流程:连接 → 接收 challenge → 发送请求 → 接收响应 → 关闭。
|
|
140
149
|
*/
|
|
141
150
|
protected _shortRpc(gatewayUrl: string, method: string, params: RpcParams): Promise<JsonObject>;
|
|
151
|
+
private _shortRpcAdmitted;
|
|
142
152
|
/** 两阶段登录 */
|
|
143
153
|
private _login;
|
|
144
154
|
/** 刷新 access_token */
|
package/dist/auth.js
CHANGED
|
@@ -112,13 +112,13 @@ function _extractPublicKey(cert) {
|
|
|
112
112
|
}
|
|
113
113
|
const CERT_CLOCK_SKEW_MS = 300_000;
|
|
114
114
|
/** 检查证书时间有效性,允许测试环境和容器之间存在短暂时钟偏差 */
|
|
115
|
-
function _ensureCertTimeValid(cert, label, nowMs) {
|
|
115
|
+
function _ensureCertTimeValid(cert, label, nowMs, clockSkewMs = CERT_CLOCK_SKEW_MS) {
|
|
116
116
|
const notBefore = new Date(cert.validFrom).getTime();
|
|
117
117
|
const notAfter = new Date(cert.validTo).getTime();
|
|
118
|
-
if (nowMs +
|
|
118
|
+
if (nowMs + clockSkewMs < notBefore) {
|
|
119
119
|
throw new AuthError(`${label} is not yet valid`);
|
|
120
120
|
}
|
|
121
|
-
if (nowMs -
|
|
121
|
+
if (nowMs - clockSkewMs > notAfter) {
|
|
122
122
|
throw new AuthError(`${label} has expired`);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -338,7 +338,7 @@ function _strictCrlRevokedSerials(pem, issuer, now) {
|
|
|
338
338
|
};
|
|
339
339
|
const thisUpdate = crlTime(tbs[offset + 2]);
|
|
340
340
|
const nextUpdate = crlTime(tbs[offset + 3]);
|
|
341
|
-
if (thisUpdate > now +
|
|
341
|
+
if (thisUpdate > now + 300 || now > nextUpdate + 300 || nextUpdate <= thisUpdate)
|
|
342
342
|
throw new AuthError('service event CRL is not current');
|
|
343
343
|
const revoked = new Set();
|
|
344
344
|
if (tbs[offset + 4]?.tag === 0x30)
|
|
@@ -401,7 +401,7 @@ function _verifyOwnershipOcsp(der, certificate, issuer, now) {
|
|
|
401
401
|
if (!responderValid)
|
|
402
402
|
throw new ValidationError('OCSP responder is not the verified issuer', { stringCode: 'invalid' });
|
|
403
403
|
const producedAt = _ownershipOcspTime(tbs[offset++]);
|
|
404
|
-
if (producedAt > now +
|
|
404
|
+
if (producedAt > now + 300 || producedAt < now - 390)
|
|
405
405
|
throw new StateError('OCSP response is not current', { stringCode: 'unavailable', retryable: true });
|
|
406
406
|
const responses = _ownershipDerChildren(tbs[offset++], 0x30);
|
|
407
407
|
let status;
|
|
@@ -429,7 +429,7 @@ function _verifyOwnershipOcsp(der, certificate, issuer, now) {
|
|
|
429
429
|
const nextUpdate = _ownershipOcspTime(_ownershipDerChildren(single[3])[0]);
|
|
430
430
|
nextRefreshAt = nextUpdate * 1000;
|
|
431
431
|
currentUntil = Math.min(currentUntil, (thisUpdate + 30) * 1000);
|
|
432
|
-
if (thisUpdate > now +
|
|
432
|
+
if (thisUpdate > now + 300 || thisUpdate < now - 330 || now > nextUpdate + 300 || nextUpdate <= thisUpdate)
|
|
433
433
|
throw new StateError('OCSP validity window is not current', { stringCode: 'unavailable', retryable: true });
|
|
434
434
|
if (single[1].tag === 0x80 && single[1].content.length === 0)
|
|
435
435
|
status = 'good';
|
|
@@ -551,6 +551,26 @@ export class AuthFlow {
|
|
|
551
551
|
// 调用方注入的内存私钥(由 AUNClient.loadIdentity 传入,不走 tokenStore 解密)
|
|
552
552
|
_memIdentity = null;
|
|
553
553
|
_identityPkiContext = '';
|
|
554
|
+
_requestAdmission = null;
|
|
555
|
+
_riskCapabilityEnabled = null;
|
|
556
|
+
_httpHandler = null;
|
|
557
|
+
setRequestAdmission(admission) { this._requestAdmission = admission; }
|
|
558
|
+
setRiskSupport(enabled) { this._riskCapabilityEnabled = enabled; }
|
|
559
|
+
setHttpHandler(handler) { this._httpHandler = handler; }
|
|
560
|
+
async _fetchRiskText(url) {
|
|
561
|
+
if (!this._httpHandler)
|
|
562
|
+
return _fetchText(url, this._verifySsl, this._net);
|
|
563
|
+
const response = await this._fetchOwnershipPki(url);
|
|
564
|
+
if (response.status < 200 || response.status >= 300)
|
|
565
|
+
throw new AuthError(`HTTP ${response.status} from ${url}`);
|
|
566
|
+
return response.body;
|
|
567
|
+
}
|
|
568
|
+
async _fetchRiskJson(url) {
|
|
569
|
+
const result = JSON.parse(await this._fetchRiskText(url));
|
|
570
|
+
if (!isJsonObject(result))
|
|
571
|
+
throw new ValidationError(`invalid JSON response from ${url}`);
|
|
572
|
+
return result;
|
|
573
|
+
}
|
|
554
574
|
constructor(opts) {
|
|
555
575
|
this._logger = opts.logger ?? _noopLogger;
|
|
556
576
|
this._tokenStore = opts.tokenStore;
|
|
@@ -941,7 +961,7 @@ export class AuthFlow {
|
|
|
941
961
|
try {
|
|
942
962
|
const cert = _loadX509(certPem);
|
|
943
963
|
if (signedAt !== undefined) {
|
|
944
|
-
_ensureCertTimeValid(cert, 'peer certificate', signedAt * 1000);
|
|
964
|
+
_ensureCertTimeValid(cert, 'peer certificate', signedAt * 1000, 0);
|
|
945
965
|
await this._verifyAuthCertChain(gatewayUrl, cert, expectedAid, signedAt);
|
|
946
966
|
if (_certSubjectCN(cert) !== expectedAid)
|
|
947
967
|
throw new AuthError(`peer cert CN mismatch: expected ${expectedAid}`);
|
|
@@ -960,7 +980,7 @@ export class AuthFlow {
|
|
|
960
980
|
if (!chain.length)
|
|
961
981
|
throw new AuthError('service event certificate chain is unavailable');
|
|
962
982
|
const current = Math.trunc(Date.now() / 1000);
|
|
963
|
-
if ([cert, ...chain].some((item) => current < Math.trunc(Date.parse(item.validFrom) / 1000) || current > Math.trunc(Date.parse(item.validTo) / 1000)))
|
|
983
|
+
if ([cert, ...chain].some((item) => current < Math.trunc(Date.parse(item.validFrom) / 1000) - 300 || current > Math.trunc(Date.parse(item.validTo) / 1000) + 300))
|
|
964
984
|
throw new AuthError('service event certificate is outside its validity window');
|
|
965
985
|
await this._verifyAuthCertChain(gatewayUrl, cert, expectedAid, undefined, true, chain);
|
|
966
986
|
const crl = await this._fetchGatewayCrl(gatewayUrl, chain[0], true);
|
|
@@ -1116,7 +1136,7 @@ export class AuthFlow {
|
|
|
1116
1136
|
const observedText = headers['x-aun-cert-observed-at'] ?? '';
|
|
1117
1137
|
const observed = Date.parse(observedText) / 1000;
|
|
1118
1138
|
const now = Date.now() / 1000;
|
|
1119
|
-
if (headers['x-aun-cert-consistency'] !== 'authoritative' || typeof state !== 'string' || !state || !headers['x-aun-cert-fingerprint'] || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/.test(observedText) || !Number.isFinite(observed) || observed > now +
|
|
1139
|
+
if (headers['x-aun-cert-consistency'] !== 'authoritative' || typeof state !== 'string' || !state || !headers['x-aun-cert-fingerprint'] || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/.test(observedText) || !Number.isFinite(observed) || observed > now + 300 || observed < now - 330)
|
|
1120
1140
|
throw unavailable('ownership certificate authoritative current metadata is unavailable');
|
|
1121
1141
|
if (state !== 'active_signing' || headers['x-aun-cert-fingerprint'] !== fingerprint)
|
|
1122
1142
|
throw new ValidationError('ownership certificate lifecycle or fingerprint is invalid', { stringCode: 'invalid' });
|
|
@@ -1132,7 +1152,7 @@ export class AuthFlow {
|
|
|
1132
1152
|
if (cert.subject.match(/(?:^|\n)CN=([^\n]+)/)?.[1] !== aid)
|
|
1133
1153
|
throw new ValidationError('ownership certificate AID mismatch', { stringCode: 'invalid' });
|
|
1134
1154
|
_ownershipCertConstraints(cert);
|
|
1135
|
-
validateAgentMdCertificate(response.body, aid, Math.trunc(now), { now: Math.trunc(now), requireCurrentValidity: true });
|
|
1155
|
+
validateAgentMdCertificate(response.body, aid, Math.trunc(Math.min(Math.max(now, Date.parse(cert.validFrom) / 1000), Date.parse(cert.validTo) / 1000)), { now: Math.trunc(now), requireCurrentValidity: true });
|
|
1136
1156
|
if (certFingerprint(response.body) !== fingerprint)
|
|
1137
1157
|
throw new ValidationError('ownership certificate DER fingerprint mismatch', { stringCode: 'invalid' });
|
|
1138
1158
|
const epoch = this._strictPkiEpoch;
|
|
@@ -1156,7 +1176,7 @@ export class AuthFlow {
|
|
|
1156
1176
|
const constraints = _ownershipCertConstraints(issuer);
|
|
1157
1177
|
if (constraints.pathLen !== undefined && index > constraints.pathLen)
|
|
1158
1178
|
throw new ValidationError('ownership certificate path length is invalid', { stringCode: 'invalid' });
|
|
1159
|
-
if (!constraints.basicPresent || !issuer.ca || !constraints.keyUsagePresent || !constraints.keyCertSign || Date.now() < Date.parse(issuer.validFrom) || Date.now() > Date.parse(issuer.validTo) || !current.checkIssued(issuer) || !current.verify(issuer.publicKey))
|
|
1179
|
+
if (!constraints.basicPresent || !issuer.ca || !constraints.keyUsagePresent || !constraints.keyCertSign || Date.now() < Date.parse(issuer.validFrom) - 300_000 || Date.now() > Date.parse(issuer.validTo) + 300_000 || !current.checkIssued(issuer) || !current.verify(issuer.publicKey))
|
|
1160
1180
|
throw new ValidationError('ownership certificate chain is invalid', { stringCode: 'invalid' });
|
|
1161
1181
|
current = issuer;
|
|
1162
1182
|
}
|
|
@@ -1200,9 +1220,9 @@ export class AuthFlow {
|
|
|
1200
1220
|
if (status !== 'good')
|
|
1201
1221
|
throw unavailable('ownership certificate revocation status is unknown');
|
|
1202
1222
|
const finalNow = Date.now();
|
|
1203
|
-
if ([cert, ...chain].some((item) => finalNow < Date.parse(item.validFrom) || finalNow > Date.parse(item.validTo)))
|
|
1223
|
+
if ([cert, ...chain].some((item) => finalNow < Date.parse(item.validFrom) - 300_000 || finalNow > Date.parse(item.validTo) + 300_000))
|
|
1204
1224
|
throw new ValidationError('ownership certificate chain is invalid', { stringCode: 'invalid' });
|
|
1205
|
-
if (finalNow - began > 30_000 || finalNow / 1000 - observed >
|
|
1225
|
+
if (finalNow - began > 30_000 || finalNow / 1000 - observed > 330)
|
|
1206
1226
|
throw unavailable('ownership certificate verification window elapsed');
|
|
1207
1227
|
return { certificate: { cert_pem: response.body, chain_valid: true, state, revoked: false, revocation_checked: true, observed_at: Math.trunc(observed) }, expiresAt: Math.min(began + 3600_000, (Math.trunc(observed) + 30) * 1000, evidence.currentUntil, evidence.nextRefreshAt, Date.parse(cert.validTo), ...chain.map((item) => Date.parse(item.validTo))) };
|
|
1208
1228
|
}
|
|
@@ -1215,6 +1235,16 @@ export class AuthFlow {
|
|
|
1215
1235
|
}
|
|
1216
1236
|
}
|
|
1217
1237
|
async _fetchOwnershipPki(url) {
|
|
1238
|
+
if (!this._httpHandler)
|
|
1239
|
+
return this._fetchOwnershipPkiDirect(url);
|
|
1240
|
+
const perform = async () => {
|
|
1241
|
+
const result = await this._fetchOwnershipPkiDirect(url);
|
|
1242
|
+
return new Response([204, 205, 304].includes(result.status) ? null : result.body, { status: result.status, headers: result.headers });
|
|
1243
|
+
};
|
|
1244
|
+
const response = await this._httpHandler(url, { method: 'GET' }, perform);
|
|
1245
|
+
return { status: response.status, headers: Object.fromEntries(response.headers), body: await response.text() };
|
|
1246
|
+
}
|
|
1247
|
+
async _fetchOwnershipPkiDirect(url) {
|
|
1218
1248
|
const fetch = (target, originalHost) => new Promise((resolve, reject) => {
|
|
1219
1249
|
const parsed = new URL(target);
|
|
1220
1250
|
const module = parsed.protocol === 'https:' ? https : http;
|
|
@@ -1279,6 +1309,15 @@ export class AuthFlow {
|
|
|
1279
1309
|
* 流程:连接 → 接收 challenge → 发送请求 → 接收响应 → 关闭。
|
|
1280
1310
|
*/
|
|
1281
1311
|
async _shortRpc(gatewayUrl, method, params) {
|
|
1312
|
+
const release = this._requestAdmission?.(`rpc:${method}`);
|
|
1313
|
+
try {
|
|
1314
|
+
return await this._shortRpcAdmitted(gatewayUrl, method, params);
|
|
1315
|
+
}
|
|
1316
|
+
finally {
|
|
1317
|
+
release?.();
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
async _shortRpcAdmitted(gatewayUrl, method, params) {
|
|
1282
1321
|
this._logger.debug(`_shortRpc enter: method=${method}, gateway=${gatewayUrl}`);
|
|
1283
1322
|
if (this._connectionFactory === null) {
|
|
1284
1323
|
const call = shortRpcViaNetworkActor(gatewayUrl, method, params);
|
|
@@ -1522,6 +1561,8 @@ export class AuthFlow {
|
|
|
1522
1561
|
inline_realtime_payload_v1: true,
|
|
1523
1562
|
agent_md_validation_v1: true,
|
|
1524
1563
|
p2p_peer_pull_v1: true,
|
|
1564
|
+
gateway_migrate_v1: true,
|
|
1565
|
+
...(this._requestAdmission && this._verifySsl && this._riskCapabilityEnabled?.() ? { risk_test_v1: true } : {}),
|
|
1525
1566
|
};
|
|
1526
1567
|
const request = {
|
|
1527
1568
|
nonce,
|
|
@@ -1636,7 +1677,8 @@ export class AuthFlow {
|
|
|
1636
1677
|
async _verifyAuthCertChain(gatewayUrl, authCert, chainAid = '', signedAt, _fresh = false, suppliedChain) {
|
|
1637
1678
|
const epoch = this._strictPkiEpoch;
|
|
1638
1679
|
const nowMs = signedAt === undefined ? Date.now() : signedAt * 1000;
|
|
1639
|
-
|
|
1680
|
+
const clockSkewMs = signedAt === undefined ? CERT_CLOCK_SKEW_MS : 0;
|
|
1681
|
+
_ensureCertTimeValid(authCert, 'auth certificate', nowMs, clockSkewMs);
|
|
1640
1682
|
const chain = suppliedChain ?? await this._loadGatewayCaChain(gatewayUrl, chainAid);
|
|
1641
1683
|
if (!chain.length) {
|
|
1642
1684
|
throw new AuthError('unable to verify auth certificate chain: missing CA chain');
|
|
@@ -1648,14 +1690,14 @@ export class AuthFlow {
|
|
|
1648
1690
|
const expiresAt = Math.min(now + this._chainCacheTtl, Date.parse(authCert.validTo), ...chain.map((cert) => Date.parse(cert.validTo)));
|
|
1649
1691
|
const chainExpiresAt = Math.min(now + this._chainCacheTtl, ...chain.map((cert) => Date.parse(cert.validTo)));
|
|
1650
1692
|
for (const caCert of chain)
|
|
1651
|
-
_ensureCertTimeValid(caCert, 'CA certificate', nowMs);
|
|
1693
|
+
_ensureCertTimeValid(caCert, 'CA certificate', nowMs, clockSkewMs);
|
|
1652
1694
|
// 检查缓存
|
|
1653
1695
|
if ((this._chainVerifiedCache.get(certKey) ?? 0) > now)
|
|
1654
1696
|
return;
|
|
1655
1697
|
// 快速路径:CA 链已通过完整验证
|
|
1656
1698
|
if ((this._gatewayCaVerified.get(cacheKey) ?? 0) > now) {
|
|
1657
1699
|
const issuer = chain[0];
|
|
1658
|
-
_ensureCertTimeValid(issuer, 'Issuer CA', nowMs);
|
|
1700
|
+
_ensureCertTimeValid(issuer, 'Issuer CA', nowMs, clockSkewMs);
|
|
1659
1701
|
if (!_isCaCert(issuer)) {
|
|
1660
1702
|
throw new AuthError('Issuer CA is not marked as CA (fast path)');
|
|
1661
1703
|
}
|
|
@@ -1673,7 +1715,7 @@ export class AuthFlow {
|
|
|
1673
1715
|
let current = authCert;
|
|
1674
1716
|
for (let i = 0; i < chain.length; i++) {
|
|
1675
1717
|
const caCert = chain[i];
|
|
1676
|
-
_ensureCertTimeValid(caCert, `CA certificate[${i}]`, nowMs);
|
|
1718
|
+
_ensureCertTimeValid(caCert, `CA certificate[${i}]`, nowMs, clockSkewMs);
|
|
1677
1719
|
if (!_checkIssuedBy(current, caCert)) {
|
|
1678
1720
|
throw new AuthError(`auth certificate issuer mismatch at chain level ${i}`);
|
|
1679
1721
|
}
|
|
@@ -1764,7 +1806,7 @@ export class AuthFlow {
|
|
|
1764
1806
|
const response = fresh ? await this._fetchOwnershipPki(url) : undefined;
|
|
1765
1807
|
if (response && response.status !== 200)
|
|
1766
1808
|
throw new AuthError('service event certificate chain is unavailable');
|
|
1767
|
-
const text = response ? response.body : await
|
|
1809
|
+
const text = response ? response.body : await this._fetchRiskText(url);
|
|
1768
1810
|
return _splitPemBundle(text);
|
|
1769
1811
|
}
|
|
1770
1812
|
/**
|
|
@@ -1819,7 +1861,7 @@ export class AuthFlow {
|
|
|
1819
1861
|
*/
|
|
1820
1862
|
async _fetchGatewayCrl(gatewayUrl, _issuerCert, fresh = false) {
|
|
1821
1863
|
const url = _gatewayHttpUrl(gatewayUrl, '/pki/crl.json');
|
|
1822
|
-
const payload = fresh ? await this._fetchFreshPkiJson(url) : await
|
|
1864
|
+
const payload = fresh ? await this._fetchFreshPkiJson(url) : await this._fetchRiskJson(url);
|
|
1823
1865
|
const crlPem = String(payload.crl_pem || '');
|
|
1824
1866
|
if (!crlPem) {
|
|
1825
1867
|
throw new AuthError('gateway CRL endpoint returned no signed CRL');
|
|
@@ -2010,7 +2052,7 @@ export class AuthFlow {
|
|
|
2010
2052
|
async _fetchGatewayOcspStatus(gatewayUrl, authCert, issuerCert, strictCurrent = false) {
|
|
2011
2053
|
const serialHex = _certSerialHex(authCert);
|
|
2012
2054
|
const url = _gatewayHttpUrl(gatewayUrl, `/pki/ocsp/${serialHex}`);
|
|
2013
|
-
const payload = strictCurrent ? await this._fetchFreshPkiJson(url) : await
|
|
2055
|
+
const payload = strictCurrent ? await this._fetchFreshPkiJson(url) : await this._fetchRiskJson(url);
|
|
2014
2056
|
const status = String(payload.status || '');
|
|
2015
2057
|
const ocspB64 = String(payload.ocsp_response || '');
|
|
2016
2058
|
if (strictCurrent) {
|
|
@@ -2301,9 +2343,9 @@ export class AuthFlow {
|
|
|
2301
2343
|
const now = Date.now();
|
|
2302
2344
|
const validFrom = new Date(cert.validFrom).getTime();
|
|
2303
2345
|
const validTo = new Date(cert.validTo).getTime();
|
|
2304
|
-
if (now < validFrom)
|
|
2346
|
+
if (now < validFrom - 300_000)
|
|
2305
2347
|
return 'cert not yet valid';
|
|
2306
|
-
if (now > validTo)
|
|
2348
|
+
if (now > validTo + 300_000)
|
|
2307
2349
|
return 'cert expired';
|
|
2308
2350
|
return '';
|
|
2309
2351
|
}
|
|
@@ -2367,7 +2409,7 @@ export class AuthFlow {
|
|
|
2367
2409
|
async _downloadRegisteredCert(gatewayUrl, aid) {
|
|
2368
2410
|
const certUrl = _gatewayHttpUrl(gatewayUrl, `/pki/cert/${aid}`);
|
|
2369
2411
|
try {
|
|
2370
|
-
const certPem = await
|
|
2412
|
+
const certPem = await this._fetchRiskText(certUrl);
|
|
2371
2413
|
if (!certPem || !certPem.includes('BEGIN CERTIFICATE')) {
|
|
2372
2414
|
return null;
|
|
2373
2415
|
}
|