- Added `MoveToTrash` method in `WebmailRepository` to move messages to the Trash folder instead of deleting them permanently. - Introduced `handleDelete` method in `mailAPI` to handle message deletion requests from the client. - Updated router to include a new route for message deletion. - Enhanced the compose page to manage draft integrity, ensuring drafts are correctly associated with sent messages. - Implemented UI changes to allow users to delete messages from the mail folder view. - Added tests to verify the correct behavior of message deletion and draft handling. - Updated database migration scripts to reconcile folder counters and ensure accurate unread counts. - Added tests for TLS-RPT report parsing and webmail repository functionalities.
96 lines
2.5 KiB
Go
96 lines
2.5 KiB
Go
package entity
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"time"
|
|
)
|
|
|
|
type TlsRptPolicy struct {
|
|
PolicyType string
|
|
SuccessCount int
|
|
FailureCount int
|
|
}
|
|
|
|
type TlsRptReport struct {
|
|
OrganizationName string
|
|
ReportID string
|
|
Domain string
|
|
DateRangeBegin time.Time
|
|
DateRangeEnd time.Time
|
|
Policies []TlsRptPolicy
|
|
}
|
|
|
|
type tlsRptJsonReport struct {
|
|
OrganizationName string `json:"organization-name"`
|
|
ReportID string `json:"report-id"`
|
|
DateRange struct {
|
|
StartDatetime string `json:"start-datetime"`
|
|
EndDatetime string `json:"end-datetime"`
|
|
} `json:"date-range"`
|
|
Policies []struct {
|
|
Policy struct {
|
|
PolicyType string `json:"policy-type"`
|
|
// RFC 8460 section 4.4 names this "policy-domain". Reading it as
|
|
// "domain" parsed every real report to a blank domain, so a stored
|
|
// report could not be attributed to the domain it was about.
|
|
Domain string `json:"policy-domain"`
|
|
} `json:"policy"`
|
|
Summary struct {
|
|
TotalSuccessfulSessionCount int `json:"total-successful-session-count"`
|
|
TotalFailureSessionCount int `json:"total-failure-session-count"`
|
|
} `json:"summary"`
|
|
} `json:"policies"`
|
|
}
|
|
|
|
// ParseTlsRptReport parses JSON or gzipped JSON TLS-RPT report.
|
|
func ParseTlsRptReport(payload []byte) (*TlsRptReport, error) {
|
|
data := payload
|
|
if isGzip(payload) {
|
|
gz, err := gzip.NewReader(bytes.NewReader(payload))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("gzip reader: %w", err)
|
|
}
|
|
defer gz.Close()
|
|
decompressed, err := io.ReadAll(gz)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decompress gzip: %w", err)
|
|
}
|
|
data = decompressed
|
|
}
|
|
|
|
var parsed tlsRptJsonReport
|
|
if err := json.Unmarshal(data, &parsed); err != nil {
|
|
return nil, fmt.Errorf("unmarshal tls-rpt json: %w", err)
|
|
}
|
|
|
|
beginTime, _ := time.Parse(time.RFC3339, parsed.DateRange.StartDatetime)
|
|
endTime, _ := time.Parse(time.RFC3339, parsed.DateRange.EndDatetime)
|
|
|
|
domain := ""
|
|
if len(parsed.Policies) > 0 {
|
|
domain = parsed.Policies[0].Policy.Domain
|
|
}
|
|
|
|
report := &TlsRptReport{
|
|
OrganizationName: parsed.OrganizationName,
|
|
ReportID: parsed.ReportID,
|
|
Domain: domain,
|
|
DateRangeBegin: beginTime,
|
|
DateRangeEnd: endTime,
|
|
}
|
|
|
|
for _, p := range parsed.Policies {
|
|
report.Policies = append(report.Policies, TlsRptPolicy{
|
|
PolicyType: p.Policy.PolicyType,
|
|
SuccessCount: p.Summary.TotalSuccessfulSessionCount,
|
|
FailureCount: p.Summary.TotalFailureSessionCount,
|
|
})
|
|
}
|
|
|
|
return report, nil
|
|
}
|