Initial commit
This commit is contained in:
commit
ccc5b0cd98
26 changed files with 1806 additions and 0 deletions
128
checker/interactive.go
Normal file
128
checker/interactive.go
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
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 sdk.CheckerInteractive. 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 sdk.CheckerInteractive. 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue