feat(protocol): enforce X-Fabric-Version negotiation on node registration

This commit is contained in:
nav
2026-05-12 11:22:18 +00:00
parent 3795aea2cb
commit 8ca5d68ba4
4 changed files with 33 additions and 3 deletions

View File

@@ -0,0 +1,7 @@
export const FABRIC_PROTOCOL_VERSION = '1';
export function normalizeVersion(input?: string): string {
if (!input) return FABRIC_PROTOCOL_VERSION;
const v = input.trim();
return v;
}

View File

@@ -6,6 +6,7 @@ import {
ForbiddenException, ForbiddenException,
Get, Get,
Headers, Headers,
HttpException,
NotFoundException, NotFoundException,
Param, Param,
ParseIntPipe, ParseIntPipe,
@@ -25,6 +26,7 @@ import {
signCanonical, signCanonical,
verifyRequestTime, verifyRequestTime,
} from '../common/hmac'; } from '../common/hmac';
import { FABRIC_PROTOCOL_VERSION, normalizeVersion } from '../common/version';
@Controller('nodes') @Controller('nodes')
export class NodesController { export class NodesController {
@@ -40,7 +42,23 @@ export class NodesController {
@Headers('x-fabric-signature') signature?: string, @Headers('x-fabric-signature') signature?: string,
@Headers('x-fabric-timestamp') timestamp?: string, @Headers('x-fabric-timestamp') timestamp?: string,
@Headers('x-fabric-nonce') nonce?: string, @Headers('x-fabric-nonce') nonce?: string,
@Headers('x-fabric-version') fabricVersion?: string,
) { ) {
const requestedVersion = normalizeVersion(fabricVersion);
if (requestedVersion !== FABRIC_PROTOCOL_VERSION) {
throw new HttpException(
{
error: {
code: 'FABRIC_VERSION_NOT_SUPPORTED',
message: `unsupported protocol version: ${requestedVersion}`,
retryable: false,
},
supportedVersion: FABRIC_PROTOCOL_VERSION,
},
400,
);
}
const secret = process.env.CENTER_SHARED_SECRET as string; const secret = process.env.CENTER_SHARED_SECRET as string;
if (!signature || !timestamp || !nonce || !verifyRequestTime(timestamp)) { if (!signature || !timestamp || !nonce || !verifyRequestTime(timestamp)) {
throw new ForbiddenException('invalid hmac headers'); throw new ForbiddenException('invalid hmac headers');
@@ -88,6 +106,7 @@ export class NodesController {
return { return {
status: 'accepted', status: 'accepted',
negotiatedVersion: FABRIC_PROTOCOL_VERSION,
node: { node: {
id: saved.id, id: saved.id,
nodeId: saved.nodeId, nodeId: saved.nodeId,

View File

@@ -66,7 +66,7 @@
- [x] 鉴权方案定稿node token / HMAC - [x] 鉴权方案定稿node token / HMAC
- [x] 注册握手协议文档化 - [x] 注册握手协议文档化
- [x] 错误码与重试策略统一 - [x] 错误码与重试策略统一
- [ ] 版本协商(`X-Fabric-Version` - [x] 版本协商(`X-Fabric-Version`
--- ---

View File

@@ -21,6 +21,7 @@
``` ```
### Required Headers ### Required Headers
- `X-Fabric-Version`: 协议版本,当前固定为 `1`
- `X-Fabric-Timestamp`: ISO8601 UTC 时间(如 `2026-05-12T11:00:00.000Z` - `X-Fabric-Timestamp`: ISO8601 UTC 时间(如 `2026-05-12T11:00:00.000Z`
- `X-Fabric-Nonce`: 随机字符串(建议 UUID - `X-Fabric-Nonce`: 随机字符串(建议 UUID
- `X-Fabric-Signature`: HMAC-SHA256 十六进制串 - `X-Fabric-Signature`: HMAC-SHA256 十六进制串
@@ -84,7 +85,10 @@ signature = HMAC_SHA256_HEX(CENTER_SHARED_SECRET, canonicalString)
## 7. 版本协商(预留) ## 7. 版本协商(预留)
当前版本:`v1` 当前版本:`v1`
后续建议在请求头增加 当前实现要求请求头:
- `X-Fabric-Version: 1` - `X-Fabric-Version: 1`
以支持协议平滑升级。 若版本不匹配Center 返回:
- `400`
- `error.code = FABRIC_VERSION_NOT_SUPPORTED`
- `supportedVersion = "1"`