Skip to content
Snippets Groups Projects
tlsrpt.go 2.46 KiB
Newer Older
ale's avatar
ale committed
package reportscollector

import (
	"compress/gzip"
	"encoding/json"
	"io"
	"net/http"
	"time"
)

type tlsrptFailure struct {
	ResultType     string `json:"result-type"`
	SendingMTA     string `json:"sending-mta-ip"`
	ReceivingMX    string `json:"receiving-mx-hostname"`
	ReceivingIP    string `json:"receiving-ip"`
	NumFailed      int    `json:"failed-session-count"`
	ErrorCode      string `json:"failure-reason-code"`
	AdditionalInfo string `json:"additional-information"`
}

type tlsrptPolicy struct {
	Policy struct {
		Type   string   `json:"policy-type"`
		Policy []string `json:"policy-string"`
		Domain string   `json:"policy-domain"`
		Mx     string   `json:"mx-host"`
	} `json:"policy"`
	Summary struct {
		NumSuccessful int `json:"total-successful-session-count"`
		NumFailed     int `json:"total-failure-session-count"`
	} `json:"summary"`
	Failures []*tlsrptFailure `json:"failure-details"`
}

// A TLS RPT report.
type tlsrpt struct {
	ReportID     string `json:"report-id"`
	Organization string `json:"organization-name"`
	ContactInfo  string `json:"contact-info"`
	DateRange    struct {
		Start time.Time `json:"start-datetime"`
		End   time.Time `json:"end-datetime"`
	} `json:"date-range"`
	Policies []*tlsrptPolicy `json:"policies"`
}

type TLSRPTHandler struct{}

func (h *TLSRPTHandler) Parse(contentType string, req *http.Request) ([]Event, error) {
	var r io.Reader
	switch contentType {
	case "application/tlsrpt+json":
		r = req.Body
	case "application/tlsrpt+gzip":
		var err error
		r, err = gzip.NewReader(req.Body)
		if err != nil {
			return nil, err
		}
	default:
		return nil, ErrNoMatch
	}

	var report tlsrpt
	if err := json.NewDecoder(r).Decode(&report); err != nil {
		return nil, err
	}

	var events []Event
	for _, p := range report.Policies {
		for _, f := range p.Failures {
			events = append(events, h.eventFromFailure(&report, p, f))
		}
	}
	return events, nil
}

func (h *TLSRPTHandler) eventFromFailure(report *tlsrpt, policy *tlsrptPolicy, failure *tlsrptFailure) Event {
	e := make(Event)
	e.Set("type", "tlsrpt")
	e.Set("event_timestamp", report.DateRange.End)
	e.Set("domain", policy.Policy.Domain)
	e.Set("report_id", report.ReportID)
	e.Set("report_organization", report.Organization)
	e.Set("tlsrpt_type", failure.ResultType)
	e.Set("sending_mta", failure.SendingMTA)
	e.Set("receiving_mx", failure.ReceivingMX)
	e.Set("receiving_ip", failure.ReceivingIP)
	e.Set("failed_session_count", failure.NumFailed)
	e.Set("failure_reason", failure.ErrorCode)
ale's avatar
ale committed
	return e
}