cadd527680
- 新增 internal/dpcred 包,统一 DeriveHy2Password + DefaultFlow agentd 与 HTTP connect handler 共享同一实现 - 新增迁移 000011:nodes 表拆分 reality_prk 私钥 / reality_pbk 公钥 reality_short_id;修正 handler_grpc.go 使用私钥字段 - 新增迁移 000012:connect_credentials 持久化凭证 实现 CredentialsForNode 修复 agent 重连 resync 原先返回空的桩 - 扩展 NodeStore 接口:ListUp / EntitlementForUser / PersistCredential / DeleteCredential;同步 grpc_test.go mock - 新增 httpapi/nodes.go:GET /nodes、POST /nodes/id/connect Hub.Push + PersistCredential + 渲染完整 sing-box client 配置 JSON POST /nodes/id/disconnect - 新增 httpapi/account.go:GET /me、GET /plans、GET /notices - 新增 httpapi/clientconfig.go:BuildClientConfig 服务端渲染 - 重写 cmd/server/main.go:手写 chi public/protected 分组 nodes.Service/Hub 在 main 构造并共享;SMTPMailer/LogMailer go build ./... && go vet ./... && go test ./... 全部通过 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 lines
1.6 KiB
Go
40 lines
1.6 KiB
Go
// Package dpcred holds the data-plane credential derivation utilities shared
|
|
// between the node agent (agentd) and the HTTP control-plane connect handler.
|
|
// The functions must produce identical output on both sides — keeping them in a
|
|
// single package is the only safe way to guarantee that.
|
|
package dpcred
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
)
|
|
|
|
// DefaultFlow is the REALITY VLESS flow used for both server inbound and client
|
|
// outbound configuration (doc/02 §3.1).
|
|
const DefaultFlow = "xtls-rprx-vision"
|
|
|
|
// DeriveHy2Password derives a node-agnostic Hysteria2 password from the opaque
|
|
// data-plane credential id (dp_uuid). The REALITY inbound uses dp_uuid directly
|
|
// as the VLESS user uuid; the Hy2 inbound cannot reuse a UUID as a password
|
|
// verbatim (it must look like an opaque secret), so it is derived from the SAME
|
|
// source — "password = dp_uuid 同源派生" — via a keyed HMAC.
|
|
//
|
|
// The derivation is deterministic given (dp_uuid, key): the control plane runs
|
|
// the exact same function when it builds the client's connect config (doc/02
|
|
// §3.1), so both sides agree without the password ever crossing the agent
|
|
// contract.
|
|
//
|
|
// When key == "" the password falls back to the raw dp_uuid (acceptable for
|
|
// dev; production always injects a key via NODE_DERIVE_KEY env).
|
|
func DeriveHy2Password(dpUUID, key string) string {
|
|
if key == "" {
|
|
return dpUUID
|
|
}
|
|
mac := hmac.New(sha256.New, []byte(key))
|
|
mac.Write([]byte(dpUUID))
|
|
sum := mac.Sum(nil)
|
|
// base64url without padding → URL/JSON-safe, 43 chars.
|
|
return base64.RawURLEncoding.EncodeToString(sum)
|
|
}
|