// 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) }