canonicalize
This commit is contained in:
41
dkim.go
41
dkim.go
@@ -2,6 +2,7 @@ package dkim
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -88,6 +89,9 @@ func Sign(email *bytes.Reader, options sigOptions) (*bytes.Reader, error) {
|
|||||||
if len(p) > 2 {
|
if len(p) > 2 {
|
||||||
return nil, ErrSignBadCanonicalization
|
return nil, ErrSignBadCanonicalization
|
||||||
}
|
}
|
||||||
|
if len(p) == 1 {
|
||||||
|
options.Canonicalization = options.Canonicalization + "/simple"
|
||||||
|
}
|
||||||
for _, c := range p {
|
for _, c := range p {
|
||||||
if c != "simple" && c != "relaxed" {
|
if c != "simple" && c != "relaxed" {
|
||||||
return nil, ErrSignBadCanonicalization
|
return nil, ErrSignBadCanonicalization
|
||||||
@@ -104,7 +108,8 @@ func Sign(email *bytes.Reader, options sigOptions) (*bytes.Reader, error) {
|
|||||||
// normalize -> strtlower
|
// normalize -> strtlower
|
||||||
hasFrom := false
|
hasFrom := false
|
||||||
for i, h := range options.Headers {
|
for i, h := range options.Headers {
|
||||||
options.Headers[i] = strings.ToLower(h)
|
h = strings.ToLower(h)
|
||||||
|
options.Headers[i] = h
|
||||||
if h == "from" {
|
if h == "from" {
|
||||||
hasFrom = true
|
hasFrom = true
|
||||||
}
|
}
|
||||||
@@ -113,7 +118,39 @@ func Sign(email *bytes.Reader, options sigOptions) (*bytes.Reader, error) {
|
|||||||
return nil, ErrSignHeaderShouldContainsFrom
|
return nil, ErrSignHeaderShouldContainsFrom
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// Normalize
|
||||||
|
//normalizedHeaders, NormalizedBody, err := normalize(email, options)
|
||||||
|
|
||||||
|
canonicalize(email, options)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func canonicalize(emailReader *bytes.Reader, options sigOptions) (headers, body []byte, err error) {
|
||||||
|
var email []byte
|
||||||
|
email, err = ioutil.ReadAll(emailReader)
|
||||||
|
emailReader.Seek(0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := bytes.SplitN(email, []byte{13, 10, 13, 10}, 2)
|
||||||
|
|
||||||
|
canonicalizations := strings.Split(options.Canonicalization, "/")
|
||||||
|
// canonicalyze body
|
||||||
|
if canonicalizations[1] == "simple" {
|
||||||
|
body = bytes.TrimRight(parts[1], "\r\n")
|
||||||
|
body = append(body, []byte{13, 10}...)
|
||||||
|
} else {
|
||||||
|
for _, line := range bytes.Split(parts[1], []byte{10}) {
|
||||||
|
println(line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println(string(parts[0]))
|
||||||
|
println("\r\n")
|
||||||
|
println(string(parts[1]))
|
||||||
|
println(string(body))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
52
dkim_test.go
52
dkim_test.go
@@ -6,20 +6,42 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
privKey = `MIICXQIBAAKBgQDNUXO+Qsl1tw+GjrqFajz0ERSEUs1FHSL/+udZRWn1Atw8gz0+
|
||||||
|
tcGqhWChBDeU9gY5sKLEAZnX3FjC/T/IbqeiSM68kS5vLkzRI84eiJrm3+IieUqI
|
||||||
|
IicsO+WYxQs+JgVx5XhpPjX4SQjHtwEC2xKkWnEv+VPgO1JWdooURcSC6QIDAQAB
|
||||||
|
AoGAM9exRgVPIS4L+Ynohu+AXJBDgfX2ZtEomUIdUGk6i+cg/RaWTFNQh2IOOBn8
|
||||||
|
ftxwTfjP4HYXBm5Y60NO66klIlzm6ci303IePmjaj8tXQiriaVA0j4hmW+xgnqQX
|
||||||
|
PubFzfnR2eWLSOGChrNFbd3YABC+qttqT6vT0KpFyLdn49ECQQD3zYCpgelb0EBo
|
||||||
|
gc5BVGkbArcknhPwO39coPqKM4csu6cgI489XpF7iMh77nBTIiy6dsDdRYXZM3bq
|
||||||
|
ELTv6K4/AkEA1BwsIZG51W5DRWaKeobykQIB6FqHLW+Zhedw7BnxS8OflYAcSWi4
|
||||||
|
uGhq0DPojmhsmUC8jUeLe79CllZNP3LU1wJBAIZcoCnI7g5Bcdr4nyxfJ4pkw4cQ
|
||||||
|
S4FT0XAZPR/YZrADo8/SWCWPdFTGSuaf17nL6vLD1zljK/skY5LwshrvUCMCQQDM
|
||||||
|
MY7ehj6DVFHYlt2LFSyhInCZscTencgK24KfGF5t1JZlwt34YaMqjAMACmi/55Fc
|
||||||
|
e7DIxW5nI/nDZrOY+EAjAkA3BHUx3PeXkXJnXjlh7nGZmk/v8tB5fiofAwfXNfL7
|
||||||
|
bz0ZrT2Caz995Dpjommh5aMpCJvUGsrYCG6/Pbha9NXl`
|
||||||
|
|
||||||
|
pubKey = `MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNUXO+Qsl1tw+GjrqFajz0ERSE
|
||||||
|
Us1FHSL/+udZRWn1Atw8gz0+tcGqhWChBDeU9gY5sKLEAZnX3FjC/T/IbqeiSM68
|
||||||
|
kS5vLkzRI84eiJrm3+IieUqIIicsO+WYxQs+JgVx5XhpPjX4SQjHtwEC2xKkWnEv
|
||||||
|
+VPgO1JWdooURcSC6QIDAQAB`
|
||||||
|
|
||||||
|
domain = "tmail.io"
|
||||||
|
|
||||||
|
selector = "test"
|
||||||
|
)
|
||||||
|
|
||||||
var email = `Received: (qmail 28277 invoked from network); 1 May 2015 09:43:37 -0000
|
var email = `Received: (qmail 28277 invoked from network); 1 May 2015 09:43:37 -0000
|
||||||
Received: (qmail 21323 invoked from network); 1 May 2015 09:48:39 -0000
|
Received: (qmail 21323 invoked from network); 1 May 2015 09:48:39 -0000
|
||||||
MIME-Version: 1.0
|
MIME-Version: 1.0
|
||||||
Date: Fri, 1 May 2015 11:48:37 +0200
|
Date: Fri, 1 May 2015 11:48:37 +0200
|
||||||
Message-ID: <CADu37kTXBeNkJdXc4bSF8DbJnXmNjkLbnswK6GzG_2yn7U7P6w@tmail.io>
|
Message-ID: <CADu37kTXBeNkJdXc4bSF8DbJnXmNjkLbnswK6GzG_2yn7U7P6w@tmail.io>
|
||||||
Subject: Test DKIM
|
Subject: Test DKIM
|
||||||
From: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@gmail.com>
|
From: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@tmail.io>
|
||||||
To: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@toorop.fr>
|
To: =?UTF-8?Q?St=C3=A9phane_Depierrepont?= <toorop@toorop.fr>
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8` + "\r\n\r\n" + `Hello world
|
||||||
|
|
||||||
|
|
||||||
Hello world
|
|
||||||
--
|
--
|
||||||
Toorop`
|
Toorop` + "\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
|
||||||
|
|
||||||
func Test_NewSigOptions(t *testing.T) {
|
func Test_NewSigOptions(t *testing.T) {
|
||||||
options := NewSigOptions()
|
options := NewSigOptions()
|
||||||
@@ -66,8 +88,22 @@ func Test_SignConfig(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// header
|
// header
|
||||||
/*options.Headers = []string{"toto"}
|
options.Headers = []string{"toto"}
|
||||||
_, err = Sign(emailReader, options)
|
_, err = Sign(emailReader, options)
|
||||||
assert.EqualError(t, err, ErrSignHeaderShouldContainsFrom.Error())*/
|
assert.EqualError(t, err, ErrSignHeaderShouldContainsFrom.Error())
|
||||||
|
|
||||||
|
options.Headers = []string{"To", "From"}
|
||||||
|
_, err = Sign(emailReader, options)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Sign(t *testing.T) {
|
||||||
|
emailReader := bytes.NewReader([]byte(email))
|
||||||
|
options := NewSigOptions()
|
||||||
|
options.PrivateKey = privKey
|
||||||
|
options.Canonicalization = "simple/relaxed"
|
||||||
|
options.Domain = domain
|
||||||
|
options.Selector = selector
|
||||||
|
emailReader, err := Sign(emailReader, options)
|
||||||
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrConfigPrivateKeyRequired when there not private key in config
|
// ErrConfigPrivateKeyRequired when there not private key in config
|
||||||
ErrSignPrivateKeyRequired = errors.New("PrivateKey is required in config")
|
ErrSignPrivateKeyRequired = errors.New("PrivateKey is required")
|
||||||
|
|
||||||
// ErrSignDomainRequired when there is no domain defined in config
|
// ErrSignDomainRequired when there is no domain defined in config
|
||||||
ErrSignDomainRequired = errors.New("Domain is required in config")
|
ErrSignDomainRequired = errors.New("Domain is required")
|
||||||
|
|
||||||
// ErrSignSelectorRequired when there is no Selcteir defined in config
|
// ErrSignSelectorRequired when there is no Selcteir defined in config
|
||||||
ErrSignSelectorRequired = errors.New("Selector is required in config")
|
ErrSignSelectorRequired = errors.New("Selector is required")
|
||||||
|
|
||||||
// If Headers is specified it should at least contain 'from'
|
// If Headers is specified it should at least contain 'from'
|
||||||
ErrSignHeaderShouldContainsFrom = errors.New("Header must contains 'from' field")
|
ErrSignHeaderShouldContainsFrom = errors.New("Header must contains 'from' field")
|
||||||
|
|||||||
Reference in New Issue
Block a user