allow mocking

This commit is contained in:
Andres Erbsen
2015-08-18 12:09:42 -07:00
parent 00fde132a7
commit 47c4e9fcb7
3 changed files with 29 additions and 29 deletions

30
dkim.go
View File

@@ -13,6 +13,7 @@ import (
"encoding/base64"
"encoding/pem"
"hash"
"net"
"regexp"
"strings"
"time"
@@ -25,8 +26,6 @@ const (
MaxHeaderLineLength = 70
)
type verifyOutput int
// sigOptions represents signing options
type SigOptions struct {
@@ -181,26 +180,36 @@ func Sign(email []byte, options SigOptions) ([]byte, error) {
return append([]byte(dHeader), email...), nil
}
func Verify(email []byte) (dkimHeader *DKIMHeader, err error) {
// parse email
func Verify(email []byte, LookupTXT func(string) ([]string, error), now func() time.Time) (dkimHeader *DKIMHeader, err error) {
if LookupTXT == nil {
LookupTXT = net.LookupTXT
}
if now == nil {
now = time.Now
}
dkimHeader, err = newDkimHeaderFromEmail(email)
if err != nil {
return
}
// we do not set query method because if it's others, validation failed earlier
pubKey, err := newPubKeyFromDnsTxt(dkimHeader.Selector, dkimHeader.Domain)
txt, err := LookupTXT(dkimHeader.Selector + "._domainkey." + dkimHeader.Domain)
if err != nil {
return nil, err
}
pubKey, err := newPubKeyFromDnsTxt(txt)
if err != nil {
return nil, err
}
// Normalize
headers, body, err := canonicalize(email, dkimHeader.MessageCanonicalization, dkimHeader.Headers)
if err != nil {
return nil, err
}
sigHash := strings.Split(dkimHeader.Algorithm, "-")
// check if hash algo are compatible
if len(sigHash) < 2 {
return nil, ErrVerifyInappropriateHashAlgo
}
compatible := false
for _, algo := range pubKey.HashAlgo {
if sigHash[1] == algo {
@@ -212,10 +221,11 @@ func Verify(email []byte) (dkimHeader *DKIMHeader, err error) {
return nil, ErrVerifyInappropriateHashAlgo
}
// expired ?
if !dkimHeader.SignatureExpiration.IsZero() && dkimHeader.SignatureExpiration.Second() < time.Now().Second() {
if !dkimHeader.SignatureExpiration.IsZero() {
if dkimHeader.SignatureExpiration.Before(now()) {
return nil, ErrVerifySignatureHasExpired
}
}
bodyHash, err := getBodyHash(body, sigHash[1], dkimHeader.BodyLength)
if err != nil {

View File

@@ -333,38 +333,38 @@ func Test_Sign(t *testing.T) {
func Test_Verify(t *testing.T) {
// no DKIM header
email := []byte(emailBase)
_, err := Verify(email)
_, err := Verify(email, nil, nil)
assert.Equal(t, ErrDkimHeaderNotFound, err)
// No From
email = []byte(signedNoFrom)
_, err = Verify(email)
_, err = Verify(email, nil, nil)
assert.Equal(t, ErrVerifyBodyHash, err)
// missing mandatory 'a' flag
email = []byte(signedMissingFlag)
_, err = Verify(email)
_, err = Verify(email, nil, nil)
assert.Error(t, err)
assert.Equal(t, ErrDkimHeaderMissingRequiredTag, err)
// missing bad algo
email = []byte(signedBadAlgo)
_, err = Verify(email)
_, err = Verify(email, nil, nil)
assert.Equal(t, ErrSignBadAlgo, err)
// relaxed
email = []byte(signedRelaxedRelaxedLength)
_, err = Verify(email)
_, err = Verify(email, nil, nil)
assert.Equal(t, ErrTesting, err)
// simple
email = []byte(signedSimpleSimpleLength)
_, err = Verify(email)
_, err = Verify(email, nil, nil)
assert.Equal(t, ErrTesting, err)
// gmail
email = []byte(fromGmail)
_, err = Verify(email)
_, err = Verify(email, nil, nil)
assert.NoError(t, err)
}

View File

@@ -4,7 +4,6 @@ import (
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"net"
"strings"
)
@@ -20,16 +19,7 @@ type pubKeyRep struct {
FlagIMustBeD bool // flag i
}
func newPubKeyFromDnsTxt(selector, domain string) (*pubKeyRep, error) {
txt, err := net.LookupTXT(selector + "._domainkey." + domain)
if err != nil {
if strings.HasSuffix(err.Error(), "no such host") {
return nil, ErrVerifyNoKeyForSignature
} else {
return nil, ErrVerifyKeyUnavailable
}
}
func newPubKeyFromDnsTxt(txt []string) (*pubKeyRep, error) {
// empty record
if len(txt) == 0 {
return nil, ErrVerifyNoKeyForSignature