The SDK split the HTTP server scaffolding into the new checker-sdk-go/checker/server subpackage. Update main.go to import server and call server.New, and isolate the interactive form code behind the standalone build tag so plugin/builtin builds skip net/http entirely.
130 lines
3.6 KiB
Go
130 lines
3.6 KiB
Go
//go:build standalone
|
|
|
|
package checker
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
|
|
sdk "git.happydns.org/checker-sdk-go/checker"
|
|
"git.happydns.org/checker-tls/contract"
|
|
)
|
|
|
|
// starttlsChoices returns the STARTTLS protocols supported by starttlsUpgraders,
|
|
// sorted, with an empty first entry meaning "speak TLS immediately".
|
|
func starttlsChoices() []string {
|
|
protos := make([]string, 0, len(starttlsUpgraders)+1)
|
|
protos = append(protos, "")
|
|
for k := range starttlsUpgraders {
|
|
protos = append(protos, k)
|
|
}
|
|
sort.Strings(protos)
|
|
return protos
|
|
}
|
|
|
|
// RenderForm satisfies server.Interactive. The fields mirror the inputs
|
|
// a producer checker would put into a contract.TLSEndpoint; a human fills
|
|
// them in directly when running the checker standalone.
|
|
func (p *tlsProvider) RenderForm() []sdk.CheckerOptionField {
|
|
return []sdk.CheckerOptionField{
|
|
{
|
|
Id: "host",
|
|
Type: "string",
|
|
Label: "Host",
|
|
Description: "Hostname or IP to probe.",
|
|
Placeholder: "example.com",
|
|
Required: true,
|
|
},
|
|
{
|
|
Id: "port",
|
|
Type: "uint",
|
|
Label: "Port",
|
|
Description: "TCP port of the TLS (or STARTTLS) endpoint.",
|
|
Default: float64(443),
|
|
Required: true,
|
|
},
|
|
{
|
|
Id: "sni",
|
|
Type: "string",
|
|
Label: "SNI",
|
|
Description: "Server name for the TLS handshake. Leave empty to reuse Host.",
|
|
Placeholder: "(defaults to Host)",
|
|
},
|
|
{
|
|
Id: "starttls",
|
|
Type: "string",
|
|
Label: "STARTTLS protocol",
|
|
Description: "Plaintext protocol to upgrade before the handshake. Leave empty for direct TLS.",
|
|
Choices: starttlsChoices(),
|
|
},
|
|
{
|
|
Id: "require",
|
|
Type: "bool",
|
|
Label: "Require STARTTLS",
|
|
Description: "When checked, a server that does not advertise STARTTLS is reported critical instead of a warning.",
|
|
},
|
|
{
|
|
Id: OptionProbeTimeoutMs,
|
|
Type: "uint",
|
|
Label: "Probe timeout (ms)",
|
|
Description: "Maximum time allowed for dial + STARTTLS + TLS handshake on the endpoint.",
|
|
Default: float64(DefaultProbeTimeoutMs),
|
|
},
|
|
}
|
|
}
|
|
|
|
// ParseForm satisfies server.Interactive. It turns the human inputs into
|
|
// a single contract.TLSEndpoint, wraps it in a DiscoveryEntry, and returns
|
|
// CheckerOptions shaped as if a happyDomain host had auto-filled
|
|
// OptionEndpoints via AutoFillDiscoveryEntries.
|
|
func (p *tlsProvider) ParseForm(r *http.Request) (sdk.CheckerOptions, error) {
|
|
host := strings.TrimSpace(r.FormValue("host"))
|
|
if host == "" {
|
|
return nil, errors.New("host is required")
|
|
}
|
|
|
|
portStr := strings.TrimSpace(r.FormValue("port"))
|
|
if portStr == "" {
|
|
return nil, errors.New("port is required")
|
|
}
|
|
port64, err := strconv.ParseUint(portStr, 10, 16)
|
|
if err != nil || port64 == 0 {
|
|
return nil, fmt.Errorf("invalid port %q: must be 1-65535", portStr)
|
|
}
|
|
|
|
starttls := strings.TrimSpace(r.FormValue("starttls"))
|
|
if starttls != "" {
|
|
if _, ok := starttlsUpgraders[starttls]; !ok {
|
|
return nil, fmt.Errorf("unsupported STARTTLS protocol %q", starttls)
|
|
}
|
|
}
|
|
|
|
ep := contract.TLSEndpoint{
|
|
Host: host,
|
|
Port: uint16(port64),
|
|
SNI: strings.TrimSpace(r.FormValue("sni")),
|
|
STARTTLS: starttls,
|
|
RequireSTARTTLS: r.FormValue("require") == "true",
|
|
}
|
|
|
|
entry, err := contract.NewEntry(ep)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("build discovery entry: %w", err)
|
|
}
|
|
|
|
opts := sdk.CheckerOptions{
|
|
OptionEndpoints: []sdk.DiscoveryEntry{entry},
|
|
}
|
|
|
|
if v := strings.TrimSpace(r.FormValue(OptionProbeTimeoutMs)); v != "" {
|
|
if n, err := strconv.Atoi(v); err == nil && n > 0 {
|
|
opts[OptionProbeTimeoutMs] = float64(n)
|
|
}
|
|
}
|
|
|
|
return opts, nil
|
|
}
|