upgrade deps; rewrite smtp session

This commit is contained in:
Aine
2024-02-19 22:55:14 +02:00
parent 10213cc7d7
commit a01720da00
277 changed files with 106832 additions and 7641 deletions

View File

@@ -2,12 +2,9 @@ package dkim
import (
"io"
"regexp"
"strings"
)
var rxReduceWS = regexp.MustCompile(`[ \t\r\n]+`)
// Canonicalization is a canonicalization algorithm.
type Canonicalization string
@@ -113,17 +110,15 @@ func (c *simpleCanonicalizer) CanonicalizeBody(w io.Writer) io.WriteCloser {
type relaxedCanonicalizer struct{}
func (c *relaxedCanonicalizer) CanonicalizeHeader(s string) string {
kv := strings.SplitN(s, ":", 2)
k := strings.TrimSpace(strings.ToLower(kv[0]))
var v string
if len(kv) > 1 {
v = rxReduceWS.ReplaceAllString(kv[1], " ")
v = strings.TrimSpace(v)
k, v, ok := strings.Cut(s, ":")
if !ok {
return strings.TrimSpace(strings.ToLower(s)) + ":" + crlf
}
k = strings.TrimSpace(strings.ToLower(k))
v = strings.Join(strings.FieldsFunc(v, func(r rune) bool {
return r == ' ' || r == '\t' || r == '\n' || r == '\r'
}), " ")
return k + ":" + v + crlf
}

View File

@@ -1,4 +1,17 @@
// Package dkim creates and verifies DKIM signatures, as specified in RFC 6376.
//
// # FAQ
//
// Why can't I verify a [net/mail.Message] directly? A [net/mail.Message]
// header is already parsed, and whitespace characters (especially continuation
// lines) are removed. Thus, the signature computed from the parsed header is
// not the same as the one computed from the raw header.
//
// How can I publish my public key? You have to add a TXT record to your DNS
// zone. See [RFC 6376 appendix C]. You can use the dkim-keygen tool included
// in go-msgauth to generate the key and the TXT record.
//
// [RFC 6376 appendix C]: https://tools.ietf.org/html/rfc6376#appendix-C
package dkim
import (

View File

@@ -66,28 +66,24 @@ func foldHeaderField(kv string) string {
return fold.String() + crlf
}
func parseHeaderField(s string) (k string, v string) {
kv := strings.SplitN(s, ":", 2)
k = strings.TrimSpace(kv[0])
if len(kv) > 1 {
v = strings.TrimSpace(kv[1])
}
return
func parseHeaderField(s string) (string, string) {
key, value, _ := strings.Cut(s, ":")
return strings.TrimSpace(key), strings.TrimSpace(value)
}
func parseHeaderParams(s string) (map[string]string, error) {
pairs := strings.Split(s, ";")
params := make(map[string]string)
for _, s := range pairs {
kv := strings.SplitN(s, "=", 2)
if len(kv) != 2 {
key, value, ok := strings.Cut(s, "=")
if !ok {
if strings.TrimSpace(s) == "" {
continue
}
return params, errors.New("dkim: malformed header params")
}
params[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
params[strings.TrimSpace(key)] = strings.TrimSpace(value)
}
return params, nil
}
@@ -149,6 +145,8 @@ func newHeaderPicker(h header) *headerPicker {
}
func (p *headerPicker) Pick(key string) string {
key = strings.ToLower(key)
at := p.picked[key]
for i := len(p.h) - 1; i >= 0; i-- {
kv := p.h[i]

View File

@@ -70,24 +70,31 @@ var queryMethods = map[QueryMethod]queryFunc{
}
func queryDNSTXT(domain, selector string, txtLookup txtLookupFunc) (*queryResult, error) {
var txts []string
var err error
if txtLookup != nil {
txts, err = txtLookup(selector + "._domainkey." + domain)
} else {
txts, err = net.LookupTXT(selector + "._domainkey." + domain)
if txtLookup == nil {
txtLookup = net.LookupTXT
}
txts, err := txtLookup(selector + "._domainkey." + domain)
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
return nil, tempFailError("key unavailable: " + err.Error())
} else if err != nil {
return nil, permFailError("no key for signature: " + err.Error())
}
// Long keys are split in multiple parts
txt := strings.Join(txts, "")
return parsePublicKey(txt)
// net.LookupTXT will concatenate strings contained in a single TXT record.
// In other words, net.LookupTXT returns one entry per TXT record, even if
// a record contains multiple strings.
//
// RFC 6376 section 3.6.2.2 says multiple TXT records lead to undefined
// behavior, so reject that.
switch len(txts) {
case 0:
return nil, permFailError("no valid key found")
case 1:
return parsePublicKey(txts[0])
default:
return nil, permFailError("multiple TXT records found for key")
}
}
func parsePublicKey(s string) (*queryResult, error) {

View File

@@ -74,7 +74,7 @@ type SignOptions struct {
//
// The whole message header and body must be written to the Signer. Close should
// always be called (either after the whole message has been written, or after
// an error occured and the signer won't be used anymore). Close may return an
// an error occurred and the signer won't be used anymore). Close may return an
// error in case signing fails.
//
// After a successful Close, Signature can be called to retrieve the

View File

@@ -293,12 +293,10 @@ func verify(h header, r io.Reader, sigField, sigValue string, options *VerifyOpt
}
// Parse algos
algos := strings.SplitN(stripWhitespace(params["a"]), "-", 2)
if len(algos) != 2 {
keyAlgo, hashAlgo, ok := strings.Cut(stripWhitespace(params["a"]), "-")
if !ok {
return verif, permFailError("malformed algorithm name")
}
keyAlgo := algos[0]
hashAlgo := algos[1]
// Check hash algo
if res.HashAlgos != nil {
@@ -457,6 +455,8 @@ func stripWhitespace(s string) string {
}, s)
}
var sigRegex = regexp.MustCompile(`(b\s*=)[^;]+`)
func removeSignature(s string) string {
return regexp.MustCompile(`(b\s*=)[^;]+`).ReplaceAllString(s, "$1")
return sigRegex.ReplaceAllString(s, "$1")
}