// Secret-helper commands: they never touch an instance, so they run // before client construction and read only their own env secrets. package main import ( "encoding/json" "fmt" "io" "os" "strings" "git.knownelement.com/ukrrs/mopac-discourse-go" ) // runWebhook implements `webhook verify SIG`: the raw delivery body on // stdin, the X-Discourse-Event-Signature value as the argument, the // secret from DISCOURSE_WEBHOOK_SECRET. Exit 0 = signature valid. func runWebhook(args []string) int { if len(args) != 2 || args[0] != "verify" { fmt.Fprintf(os.Stderr, "webhook needs: verify SIG (delivery body on stdin)\n\n%s", usage) return 1 } secret, err := discourse.WebhookSecretFromEnv() if err != nil { fmt.Fprintf(os.Stderr, "discourse-go: %v\n", err) return 1 } body, err := io.ReadAll(os.Stdin) if err != nil { fmt.Fprintf(os.Stderr, "discourse-go: read stdin: %v\n", err) return 1 } if err := discourse.VerifyWebhook(secret, body, args[1]); err != nil { fmt.Fprintf(os.Stderr, "discourse-go: %v\n", err) return 2 } fmt.Printf("verified %d bytes\n", len(body)) return 0 } // runSSO implements `sso verify SSO SIG`: checks a Discourse Connect // login redirect's sso/sig pair against DISCOURSE_SSO_SECRET and prints // the decoded payload as JSON. Exit 0 = signature valid. func runSSO(args []string) int { if len(args) != 3 || args[0] != "verify" { fmt.Fprintf(os.Stderr, "sso needs: verify SSO SIG (sso+sig from the login URL)\n\n%s", usage) return 1 } secret, err := discourse.SSOSecretFromEnv() if err != nil { fmt.Fprintf(os.Stderr, "discourse-go: %v\n", err) return 1 } vals, err := discourse.VerifySSO(secret, args[1], args[2]) if err != nil { fmt.Fprintf(os.Stderr, "discourse-go: %v\n", err) return 2 } obj := map[string]string{} for k, v := range vals { obj[k] = strings.Join(v, ",") } enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") if err := enc.Encode(obj); err != nil { fmt.Fprintf(os.Stderr, "discourse-go: encode payload: %v\n", err) return 1 } return 0 }