mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-22 15:27:02 +00:00
dkim: Implement internal dkim signing and verification
This patch implements internal DKIM signing and verification.
This commit is contained in:
77
internal/dkim/message.go
Normal file
77
internal/dkim/message.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package dkim
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type header struct {
|
||||
Name string
|
||||
Value string
|
||||
Source string
|
||||
}
|
||||
|
||||
type headers []header
|
||||
|
||||
// FindAll the headers with the given name, in order of appearance.
|
||||
func (h headers) FindAll(name string) headers {
|
||||
hs := make(headers, 0)
|
||||
for _, header := range h {
|
||||
if strings.EqualFold(header.Name, name) {
|
||||
hs = append(hs, header)
|
||||
}
|
||||
}
|
||||
return hs
|
||||
}
|
||||
|
||||
var errInvalidHeader = errors.New("invalid header")
|
||||
|
||||
// Parse a RFC822 message, return the headers, body, and error if any.
|
||||
// We expect it to only contain CRLF line endings.
|
||||
// Does NOT touch whitespace, this is important to preserve the original
|
||||
// message and headers, which is required for the signature.
|
||||
func parseMessage(message string) (headers, string, error) {
|
||||
headers := make(headers, 0)
|
||||
lines := strings.Split(message, "\r\n")
|
||||
eoh := 0
|
||||
for i, line := range lines {
|
||||
if line == "" {
|
||||
eoh = i
|
||||
break
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") {
|
||||
// Continuation of the previous header.
|
||||
if len(headers) == 0 {
|
||||
return nil, "", fmt.Errorf(
|
||||
"%w: bad continuation", errInvalidHeader)
|
||||
}
|
||||
headers[len(headers)-1].Value += "\r\n" + line
|
||||
headers[len(headers)-1].Source += "\r\n" + line
|
||||
} else {
|
||||
// New header.
|
||||
h, err := parseHeader(line)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
headers = append(headers, h)
|
||||
}
|
||||
}
|
||||
|
||||
return headers, strings.Join(lines[eoh+1:], "\r\n"), nil
|
||||
}
|
||||
|
||||
func parseHeader(line string) (header, error) {
|
||||
name, value, found := strings.Cut(line, ":")
|
||||
if !found {
|
||||
return header{}, fmt.Errorf("%w: no colon", errInvalidHeader)
|
||||
}
|
||||
|
||||
return header{
|
||||
Name: name,
|
||||
Value: value,
|
||||
Source: line,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user