Feature(Go): issue-token subcommand for minting customer JWTs
This commit is contained in:
@@ -661,7 +661,72 @@ func splitCSV(s string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// runIssueToken handles the "issue-token" subcommand. It mints a customer JWT
|
||||
// signed with the operator's RSA private key and prints it to stdout.
|
||||
//
|
||||
// The private key path defaults to $YAMA_LICENSE_PRIVATE_KEY so that on the
|
||||
// authorization server — where env vars are already configured — only the
|
||||
// per-customer fields need to be specified:
|
||||
//
|
||||
// server issue-token -sub customer-acme [-tier paid|trial] [-devices 10] [-ttl 8760h]
|
||||
//
|
||||
// If neither -key nor $YAMA_LICENSE_PRIVATE_KEY is set, the command exits
|
||||
// with a clear error rather than silently using a wrong default.
|
||||
func runIssueToken(args []string) {
|
||||
fs := flag.NewFlagSet("issue-token", flag.ExitOnError)
|
||||
// Default from env so the operator doesn't need to retype the path.
|
||||
keyPath := fs.String("key", os.Getenv(licensing.EnvLicensePrivKeyPath),
|
||||
"Path to RSA private key PEM (PKCS#1 or PKCS#8); default: $"+licensing.EnvLicensePrivKeyPath)
|
||||
sub := fs.String("sub", "", "Customer identifier — unique string, e.g. \"customer-acme\" (required)")
|
||||
tier := fs.String("tier", licensing.TierPaid, "License tier: \"paid\" or \"trial\"")
|
||||
devices := fs.Int("devices", 10, "Max concurrent managed devices")
|
||||
ttl := fs.Duration("ttl", 365*24*time.Hour, "Token validity period, e.g. 8760h (1 year)")
|
||||
fs.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "Usage: %s issue-token [flags]\n\nFlags:\n", os.Args[0])
|
||||
fs.PrintDefaults()
|
||||
fmt.Fprintf(os.Stderr, "\nExample:\n %s issue-token -sub customer-acme -tier paid -devices 20 -ttl 8760h\n", os.Args[0])
|
||||
}
|
||||
_ = fs.Parse(args)
|
||||
|
||||
var errs []string
|
||||
if *keyPath == "" {
|
||||
errs = append(errs, fmt.Sprintf("-key or $%s is required", licensing.EnvLicensePrivKeyPath))
|
||||
}
|
||||
if *sub == "" {
|
||||
errs = append(errs, "-sub is required")
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
for _, e := range errs {
|
||||
fmt.Fprintln(os.Stderr, "error:", e)
|
||||
}
|
||||
fmt.Fprintln(os.Stderr)
|
||||
fs.Usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
privKey, err := licensing.LoadRSAPrivateKey(*keyPath)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error loading private key: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
token, err := licensing.Issue(privKey, *sub, *tier, *devices, *ttl)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error issuing token: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(token)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Subcommand dispatch: "server issue-token ..." runs the token-minting
|
||||
// helper and exits without starting the server.
|
||||
if len(os.Args) > 1 && os.Args[1] == "issue-token" {
|
||||
runIssueToken(os.Args[2:])
|
||||
return
|
||||
}
|
||||
|
||||
// Parse command line flags
|
||||
portStr := flag.String("port", "6543", "Server listen ports (semicolon-separated, e.g. 6543;6544;6545)")
|
||||
flag.StringVar(portStr, "p", "6543", "Server listen ports (shorthand)")
|
||||
|
||||
Reference in New Issue
Block a user