-
-
Notifications
You must be signed in to change notification settings - Fork 35
/
mailreply00_test.go
98 lines (88 loc) · 3.59 KB
/
mailreply00_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Copyright 2023 Matthew Holt
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package acmez
import (
"bytes"
"crypto/sha256"
"encoding/base64"
"fmt"
"io"
"net/mail"
"strings"
"testing"
"github.com/mholt/acmez/v2/acme"
)
func TestMailReplyChallengeResponse(t *testing.T) {
tokenPart2 := "x6I65YvEk6xC4KV0QMvdJw" // token-part2, obtained through JSON response
thumbprint := "hC4xyXNn8ZDH4yrcp93Zj3qgQs7LyT_GUL45YD7IVMQ" // fake (raw) base64url encoded account public key
c := acme.Challenge{
From: "acmeca@test.example.com",
Identifier: acme.Identifier{Type: "email", Value: "client@test.example.com"},
Token: tokenPart2,
KeyAuthorization: fmt.Sprintf("%s.%s", tokenPart2, thumbprint), // with email-reply-00 only 2nd half of token is prefixed
}
subject := "ACME: V4nE8NhYh6edBpfQTg5qqQ" // (raw) base64url encoded token-part1
// simulate decoding / (re)encoding logic to constuct key authorization
tp1, err := base64.RawURLEncoding.DecodeString("V4nE8NhYh6edBpfQTg5qqQ")
if err != nil {
t.Fatal(err)
}
tp2, err := base64.RawURLEncoding.DecodeString(tokenPart2)
if err != nil {
t.Fatal(err)
}
token := base64.RawURLEncoding.EncodeToString(append(tp1, tp2...))
h := sha256.Sum256([]byte(fmt.Sprintf("%s.%s", token, thumbprint)))
keyAuthorization := base64.RawURLEncoding.EncodeToString(h[:])
if keyAuthorization != "Fjt2SD7KoqSt3I6jwgg8ljjkP9Er7h1w0wF0UihvQIU" {
t.Errorf("expected key authorization to be %q, got %q", "Fjt2SD7KoqSt3I6jwgg8ljjkP9Er7h1w0wF0UihvQIU", keyAuthorization)
}
// generate the actual response
got, err := MailReplyChallengeResponse(c, subject, "messageId", "")
if err != nil {
t.Fatal(err)
}
// parse the email message
msg, err := mail.ReadMessage(bytes.NewBufferString(got))
if err != nil {
t.Fatal(err)
}
// validate email header properties
if to := msg.Header.Get("to"); to != "acmeca@test.example.com" {
t.Errorf("expected To to be %q, got %q", "acmeca@test.example.com", to)
}
if from := msg.Header.Get("from"); from != "client@test.example.com" {
t.Errorf("expected from to be %q, got %q", "client@test.example.com", from)
}
if replyTo := msg.Header.Get("in-reply-to"); replyTo != "messageId" {
t.Errorf("expected content type to be %q, got %q", "messageId", replyTo)
}
if subject := msg.Header.Get("subject"); subject != "RE: ACME: V4nE8NhYh6edBpfQTg5qqQ" {
t.Errorf("expected subject to be %q, got %q", "RE: ACME: V4nE8NhYh6edBpfQTg5qqQ", subject)
}
if contentType := msg.Header.Get("content-type"); contentType != "text/plain" {
t.Errorf("expected content type to be %q, got %q", "text/plain", contentType)
}
body, err := io.ReadAll(msg.Body)
if err != nil {
t.Fatal(err)
}
// validate the response
trimmed, _ := strings.CutPrefix(strings.TrimSpace(string(body)), "-----BEGIN ACME RESPONSE-----")
trimmed, _ = strings.CutSuffix(trimmed, "-----END ACME RESPONSE-----")
trimmed = strings.TrimSpace(trimmed)
if trimmed != "Fjt2SD7KoqSt3I6jwgg8ljjkP9Er7h1w0wF0UihvQIU" {
t.Errorf("expected ACME challenge response to be %q, got %q", "Fjt2SD7KoqSt3I6jwgg8ljjkP9Er7h1w0wF0UihvQIU", trimmed)
}
}