// Package webapisrv implements the server-side of the webapi. package webapisrv // In a separate package from webapi, so webapi.Client can be used and imported // without including all mox internals. Documentation for the functions is in // ../webapi/client.go. import ( "bytes" "context" cryptorand "crypto/rand" "encoding/base64" "encoding/json" "errors" "fmt" htmltemplate "html/template" "io" "log/slog" "mime" "mime/multipart" "net/http" "net/textproto" "reflect" "runtime/debug" "slices" "strings" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/mjl-/bstore" "github.com/mjl-/mox/dkim" "github.com/mjl-/mox/dns" "github.com/mjl-/mox/message" "github.com/mjl-/mox/metrics" "github.com/mjl-/mox/mlog" "github.com/mjl-/mox/mox-" "github.com/mjl-/mox/moxio" "github.com/mjl-/mox/moxvar" "github.com/mjl-/mox/queue" "github.com/mjl-/mox/smtp" "github.com/mjl-/mox/store" "github.com/mjl-/mox/webapi" "github.com/mjl-/mox/webauth" "github.com/mjl-/mox/webops" ) var pkglog = mlog.New("webapi", nil) var ( // Similar between ../webmail/webmail.go:/metricSubmission and ../smtpserver/server.go:/metricSubmission and ../webapisrv/server.go:/metricSubmission metricSubmission = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "mox_webapi_submission_total", Help: "Webapi message submission results, known values (those ending with error are server errors): ok, badfrom, messagelimiterror, recipientlimiterror, queueerror, storesenterror.", }, []string{ "result", }, ) metricServerErrors = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "mox_webapi_errors_total", Help: "Webapi server errors, known values: dkimsign, submit.", }, []string{ "error", }, ) metricResults = promauto.NewCounterVec( prometheus.CounterOpts{ Name: "mox_webapi_results_total", Help: "HTTP webapi results by method and result.", }, []string{"method", "result"}, // result: "badauth", "ok", or error code ) metricDuration = promauto.NewHistogramVec( prometheus.HistogramOpts{ Name: "mox_webapi_duration_seconds", Help: "HTTP webhook call duration.", Buckets: []float64{0.01, 0.05, 0.1, 0.5, 1, 5, 10, 20, 30}, }, []string{"method"}, ) ) // We pass the request to the handler so the TLS info can be used for // the Received header in submitted messages. Most API calls need just the // account name. type ctxKey string var requestInfoCtxKey ctxKey = "requestInfo" type requestInfo struct { Log mlog.Log LoginAddress string Account *store.Account Response http.ResponseWriter // For setting headers for non-JSON responses. Request *http.Request // For Proto and TLS connection state during message submit. } // todo: show a curl invocation on the method pages var docsMethodTemplate = htmltemplate.Must(htmltemplate.New("method").Parse(`