Feat(go): add Signer interface + License Server for multi-customer deployments

This commit is contained in:
yuanyuanxiang
2026-05-20 15:11:32 +02:00
parent e264e092f6
commit d808462fe1
14 changed files with 1798 additions and 29 deletions

View File

@@ -0,0 +1,44 @@
// Package licensing provides pluggable signing strategies for the per-login
// CMD_MASTERSETTING signature. Three modes are picked at startup by env var:
//
// - LocalSigner (YAMA_SIGN_PASSWORD set): operator's own deployment.
// Signs directly with the HMAC master key. Optionally serves as License
// Server for RemoteSigner deployments (see server.go) when
// YAMA_LICENSE_HTTP_ADDR is also set.
//
// - RemoteSigner (YAMA_LICENSE_SERVER + YAMA_LICENSE_TOKEN set): customer
// deployments. Never sees the HMAC master key — each new device login
// does an HTTPS POST to the operator's License Server to fetch a
// signature. Successful results are cached for 24h so transient
// License Server outages don't break new logins.
//
// - NoOpSigner (neither set): free-tier mode. Returns empty signature so
// the client's private library refuses screen/file features; device
// list keeps working.
//
// The Sign call is on the per-login critical path — keep it fast.
// LocalSigner is microseconds (HMAC). RemoteSigner is one HTTPS round-trip
// on cache miss (~100-300 ms), zero on cache hit.
package licensing
// Signer produces the per-login signature for CMD_MASTERSETTING.
//
// Sign returns the 64-char lowercase hex HMAC-SHA256 of "<startTime>|<clientID>"
// keyed by the deployment's master HMAC secret. Returning "" means "no
// signature available" — sendMasterSetting will ship a zeroed Signature[64]
// field, and the client's private library will refuse screen/file init.
type Signer interface {
// Sign generates the signature for a new device login. SHOULD be quick
// (sub-300ms target). Returning ("", nil) is allowed and means "this
// deployment doesn't sign" (NoOpSigner). Returning ("", err) means a
// transient failure — callers ship zeroed signature and log the error;
// the device can retry by reconnecting.
Sign(startTime, clientID string) (string, error)
// Mode returns a short identifier for logging: "local", "remote", "noop".
Mode() string
// Close releases background resources (HTTP keepalives, caches).
// Idempotent.
Close() error
}