Skip to content

Commit 3bf222f

Browse files
authored
[Fix] - Fuzz tests, linting, http methods (#94)
* feat(email): block header injection in template aliases Add validation to detect and reject template aliases containing carriage returns or line feeds to prevent header injection attacks. Apply this validation in SendTemplatedEmail and SendTemplatedEmailBatch to ensure all template aliases are safe before sending emails. Include comprehensive tests to verify valid aliases pass and malicious aliases trigger errors, enhancing email security. * refactor: use http.Method constants for HTTP requests Replace string literals for HTTP methods with the standard net/http.MethodGet, MethodPost, MethodDelete, etc. constants across multiple packages and files including inbound_rules_triggers, bounce, sender_signatures, data_removals, email, and the test router. This improves code readability, consistency, and reduces the risk of typos in method strings. Additionally, update TestRouter to use http.Request parameter names and method constants for clarity. * refactor: use http.Method constants and add PushTemplates tests Replace raw HTTP method strings with standard http.Method constants throughout template client methods for improved consistency and clarity. Add comprehensive tests for PushTemplates API including simulation mode, verifying request payload, headers, and response unmarshaling to ensure correct client behavior and robustness when pushing templates between servers.
1 parent d851f73 commit 3bf222f

15 files changed

+434
-98
lines changed

bounce.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/json"
66
"fmt"
7+
"net/http"
78
"net/url"
89
"time"
910
)
@@ -32,7 +33,7 @@ func (client *Client) GetDeliveryStats(ctx context.Context) (DeliveryStats, erro
3233
res := DeliveryStats{}
3334
path := "deliverystats"
3435
err := client.doRequest(ctx, parameters{
35-
Method: "GET",
36+
Method: http.MethodGet,
3637
Path: path,
3738
TokenType: serverToken,
3839
}, &res)
@@ -99,7 +100,7 @@ func (client *Client) GetBounces(ctx context.Context, count, offset int64, optio
99100
path := fmt.Sprintf("bounces?%s", values.Encode())
100101

101102
err := client.doRequest(ctx, parameters{
102-
Method: "GET",
103+
Method: http.MethodGet,
103104
Path: path,
104105
TokenType: serverToken,
105106
}, &res)
@@ -111,7 +112,7 @@ func (client *Client) GetBounce(ctx context.Context, bounceID int64) (Bounce, er
111112
res := Bounce{}
112113
path := fmt.Sprintf("bounces/%v", bounceID)
113114
err := client.doRequest(ctx, parameters{
114-
Method: "GET",
115+
Method: http.MethodGet,
115116
Path: path,
116117
TokenType: serverToken,
117118
}, &res)
@@ -127,7 +128,7 @@ func (client *Client) GetBounceDump(ctx context.Context, bounceID int64) (string
127128
res := dumpResponse{}
128129
path := fmt.Sprintf("bounces/%v/dump", bounceID)
129130
err := client.doRequest(ctx, parameters{
130-
Method: "GET",
131+
Method: http.MethodGet,
131132
Path: path,
132133
TokenType: serverToken,
133134
}, &res)
@@ -146,7 +147,7 @@ func (client *Client) ActivateBounce(ctx context.Context, bounceID int64) (Bounc
146147
res := activateBounceResponse{}
147148
path := fmt.Sprintf("bounces/%v/activate", bounceID)
148149
err := client.doRequest(ctx, parameters{
149-
Method: "PUT",
150+
Method: http.MethodPut,
150151
Path: path,
151152
TokenType: serverToken,
152153
}, &res)
@@ -162,7 +163,7 @@ func (client *Client) GetBouncedTags(ctx context.Context) ([]string, error) {
162163
var raw json.RawMessage
163164
path := "bounces/tags"
164165
err := client.doRequest(ctx, parameters{
165-
Method: "GET",
166+
Method: http.MethodGet,
166167
Path: path,
167168
TokenType: serverToken,
168169
}, &raw)

data_removals.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package postmark
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"time"
78
)
89

@@ -30,7 +31,7 @@ type DataRemovalResponse struct {
3031
func (client *Client) CreateDataRemoval(ctx context.Context, request DataRemovalRequest) (DataRemovalResponse, error) {
3132
res := DataRemovalResponse{}
3233
err := client.doRequest(ctx, parameters{
33-
Method: "POST",
34+
Method: http.MethodPost,
3435
Path: "data-removals",
3536
Payload: request,
3637
TokenType: accountToken,
@@ -42,7 +43,7 @@ func (client *Client) CreateDataRemoval(ctx context.Context, request DataRemoval
4243
func (client *Client) GetDataRemovalStatus(ctx context.Context, id int64) (DataRemovalResponse, error) {
4344
res := DataRemovalResponse{}
4445
err := client.doRequest(ctx, parameters{
45-
Method: "GET",
46+
Method: http.MethodGet,
4647
Path: fmt.Sprintf("data-removals/%d", id),
4748
TokenType: accountToken,
4849
}, &res)

domains.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func (client *Client) GetDomains(ctx context.Context, count, offset int) (Domain
111111
values.Add("offset", fmt.Sprintf("%d", offset))
112112

113113
err := client.doRequest(ctx, parameters{
114-
Method: "GET",
114+
Method: http.MethodGet,
115115
Path: fmt.Sprintf("domains?%s", values.Encode()),
116116
TokenType: accountToken,
117117
}, &res)

email.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"net/http"
78
"time"
89
)
910

@@ -85,7 +86,7 @@ type EmailResponse struct {
8586
func (client *Client) SendEmail(ctx context.Context, email Email) (EmailResponse, error) {
8687
res := EmailResponse{}
8788
err := client.doRequest(ctx, parameters{
88-
Method: "POST",
89+
Method: http.MethodPost,
8990
Path: "email",
9091
Payload: email,
9192
TokenType: serverToken,
@@ -104,7 +105,7 @@ func (client *Client) SendEmail(ctx context.Context, email Email) (EmailResponse
104105
func (client *Client) SendEmailBatch(ctx context.Context, emails []Email) ([]EmailResponse, error) {
105106
var res []EmailResponse
106107
err := client.doRequest(ctx, parameters{
107-
Method: "POST",
108+
Method: http.MethodPost,
108109
Path: "email/batch",
109110
Payload: emails,
110111
TokenType: serverToken,

inbound_rules_triggers.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package postmark
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"net/url"
78
)
89

@@ -38,7 +39,7 @@ func (client *Client) GetInboundRuleTriggers(ctx context.Context, count, offset
3839
values.Add("offset", fmt.Sprintf("%d", offset))
3940

4041
err := client.doRequest(ctx, parameters{
41-
Method: "GET",
42+
Method: http.MethodGet,
4243
Path: fmt.Sprintf("triggers/inboundrules?%s", values.Encode()),
4344
TokenType: serverToken,
4445
}, &res)
@@ -55,7 +56,7 @@ func (client *Client) CreateInboundRuleTrigger(ctx context.Context, rule string)
5556
}
5657

5758
err := client.doRequest(ctx, parameters{
58-
Method: "POST",
59+
Method: http.MethodPost,
5960
Path: "triggers/inboundrules",
6061
Payload: requestData,
6162
TokenType: serverToken,
@@ -68,7 +69,7 @@ func (client *Client) CreateInboundRuleTrigger(ctx context.Context, rule string)
6869
func (client *Client) DeleteInboundRuleTrigger(ctx context.Context, triggerID int64) error {
6970
res := APIError{}
7071
err := client.doRequest(ctx, parameters{
71-
Method: "DELETE",
72+
Method: http.MethodDelete,
7273
Path: fmt.Sprintf("triggers/inboundrules/%d", triggerID),
7374
TokenType: serverToken,
7475
}, &res)

messages_inbound.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package postmark
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"net/mail"
78
"net/url"
89
"time"
@@ -61,7 +62,7 @@ func (x InboundMessage) Time() (time.Time, error) {
6162
func (client *Client) GetInboundMessage(ctx context.Context, messageID string) (InboundMessage, error) {
6263
res := InboundMessage{}
6364
err := client.doRequest(ctx, parameters{
64-
Method: "GET",
65+
Method: http.MethodGet,
6566
Path: fmt.Sprintf("messages/inbound/%s/details", messageID),
6667
TokenType: serverToken,
6768
}, &res)
@@ -88,7 +89,7 @@ func (client *Client) GetInboundMessages(ctx context.Context, count, offset int6
8889
}
8990

9091
err := client.doRequest(ctx, parameters{
91-
Method: "GET",
92+
Method: http.MethodGet,
9293
Path: fmt.Sprintf("messages/inbound?%s", values.Encode()),
9394
TokenType: serverToken,
9495
}, &res)
@@ -100,7 +101,7 @@ func (client *Client) GetInboundMessages(ctx context.Context, count, offset int6
100101
func (client *Client) BypassInboundMessage(ctx context.Context, messageID string) error {
101102
res := APIError{}
102103
err := client.doRequest(ctx, parameters{
103-
Method: "PUT",
104+
Method: http.MethodPut,
104105
Path: fmt.Sprintf("messages/inbound/%s/bypass", messageID),
105106
TokenType: serverToken,
106107
}, &res)
@@ -116,7 +117,7 @@ func (client *Client) BypassInboundMessage(ctx context.Context, messageID string
116117
func (client *Client) RetryInboundMessage(ctx context.Context, messageID string) error {
117118
res := APIError{}
118119
err := client.doRequest(ctx, parameters{
119-
Method: "PUT",
120+
Method: http.MethodPut,
120121
Path: fmt.Sprintf("messages/inbound/%s/retry", messageID),
121122
TokenType: serverToken,
122123
}, &res)

messages_outbound.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package postmark
33
import (
44
"context"
55
"fmt"
6+
"net/http"
67
"net/url"
78
"time"
89
)
@@ -66,7 +67,7 @@ type MessageEvent struct {
6667
func (client *Client) GetOutboundMessage(ctx context.Context, messageID string) (OutboundMessage, error) {
6768
res := OutboundMessage{}
6869
err := client.doRequest(ctx, parameters{
69-
Method: "GET",
70+
Method: http.MethodGet,
7071
Path: fmt.Sprintf("messages/outbound/%s/details", messageID),
7172
TokenType: serverToken,
7273
}, &res)
@@ -77,7 +78,7 @@ func (client *Client) GetOutboundMessage(ctx context.Context, messageID string)
7778
func (client *Client) GetOutboundMessageDump(ctx context.Context, messageID string) (string, error) {
7879
res := dumpResponse{}
7980
err := client.doRequest(ctx, parameters{
80-
Method: "GET",
81+
Method: http.MethodGet,
8182
Path: fmt.Sprintf("messages/outbound/%s/dump", messageID),
8283
TokenType: serverToken,
8384
}, &res)
@@ -105,7 +106,7 @@ func (client *Client) GetOutboundMessages(ctx context.Context, count, offset int
105106
}
106107

107108
err := client.doRequest(ctx, parameters{
108-
Method: "GET",
109+
Method: http.MethodGet,
109110
Path: fmt.Sprintf("messages/outbound?%s", values.Encode()),
110111
TokenType: serverToken,
111112
}, &res)
@@ -188,7 +189,7 @@ func (client *Client) GetOutboundMessagesOpens(ctx context.Context, count, offse
188189
}
189190

190191
err := client.doRequest(ctx, parameters{
191-
Method: "GET",
192+
Method: http.MethodGet,
192193
Path: fmt.Sprintf("messages/outbound/opens?%s", values.Encode()),
193194
TokenType: serverToken,
194195
}, &res)
@@ -205,7 +206,7 @@ func (client *Client) GetOutboundMessageOpens(ctx context.Context, messageID str
205206
values.Add("offset", fmt.Sprintf("%d", offset))
206207

207208
err := client.doRequest(ctx, parameters{
208-
Method: "GET",
209+
Method: http.MethodGet,
209210
Path: fmt.Sprintf("messages/outbound/opens/%s?%s", messageID, values.Encode()),
210211
TokenType: serverToken,
211212
}, &res)
@@ -228,7 +229,7 @@ func (client *Client) GetOutboundMessagesClicks(ctx context.Context, count, offs
228229
}
229230

230231
err := client.doRequest(ctx, parameters{
231-
Method: "GET",
232+
Method: http.MethodGet,
232233
Path: fmt.Sprintf("messages/outbound/clicks?%s", values.Encode()),
233234
TokenType: serverToken,
234235
}, &res)
@@ -245,7 +246,7 @@ func (client *Client) GetOutboundMessageClicks(ctx context.Context, messageID st
245246
values.Add("offset", fmt.Sprintf("%d", offset))
246247

247248
err := client.doRequest(ctx, parameters{
248-
Method: "GET",
249+
Method: http.MethodGet,
249250
Path: fmt.Sprintf("messages/outbound/clicks/%s?%s", messageID, values.Encode()),
250251
TokenType: serverToken,
251252
}, &res)

postmark_fuzz_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func FuzzDoRequestJSONUnmarshal(f *testing.F) {
4646

4747
// Test that the function doesn't panic with malformed JSON
4848
err := client.doRequest(context.Background(), parameters{
49-
Method: "GET",
49+
Method: http.MethodGet,
5050
Path: "test",
5151
TokenType: serverToken,
5252
}, &result)
@@ -97,7 +97,7 @@ func FuzzAPIErrorHandling(f *testing.F) {
9797
var result map[string]interface{}
9898

9999
err := client.doRequest(context.Background(), parameters{
100-
Method: "GET",
100+
Method: http.MethodGet,
101101
Path: "test",
102102
TokenType: serverToken,
103103
}, &result)
@@ -175,7 +175,7 @@ func FuzzJSONPayloadMarshaling(f *testing.F) {
175175

176176
// Test that marshaling doesn't panic with complex payloads
177177
err := client.doRequest(context.Background(), parameters{
178-
Method: "POST",
178+
Method: http.MethodPost,
179179
Path: "test",
180180
Payload: payload,
181181
TokenType: serverToken,

postmark_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func (s *PostmarkTestSuite) TestDoRequestWithPayload() {
5656

5757
var result map[string]string
5858
err := s.client.doRequest(context.Background(), parameters{
59-
Method: "POST",
59+
Method: http.MethodPost,
6060
Path: "test",
6161
TokenType: serverToken,
6262
Payload: payload,
@@ -77,7 +77,7 @@ func (s *PostmarkTestSuite) TestDoRequestWithAccountToken() {
7777

7878
var result map[string]string
7979
err := s.client.doRequest(context.Background(), parameters{
80-
Method: "GET",
80+
Method: http.MethodGet,
8181
Path: "account-test",
8282
TokenType: accountToken,
8383
}, &result)
@@ -94,7 +94,7 @@ func (s *PostmarkTestSuite) TestDoRequestHTTPError() {
9494

9595
var result map[string]string
9696
err := s.client.doRequest(context.Background(), parameters{
97-
Method: "GET",
97+
Method: http.MethodGet,
9898
Path: "error-test",
9999
TokenType: serverToken,
100100
}, &result)
@@ -108,7 +108,7 @@ func (s *PostmarkTestSuite) TestDoRequestContextCancellation() {
108108

109109
var result map[string]string
110110
err := s.client.doRequest(ctx, parameters{
111-
Method: "GET",
111+
Method: http.MethodGet,
112112
Path: "test",
113113
TokenType: serverToken,
114114
}, &result)
@@ -124,7 +124,7 @@ func (s *PostmarkTestSuite) TestDoRequestInvalidJSON() {
124124

125125
var result map[string]string
126126
err := s.client.doRequest(context.Background(), parameters{
127-
Method: "GET",
127+
Method: http.MethodGet,
128128
Path: "invalid-json",
129129
TokenType: serverToken,
130130
}, &result)

sender_signatures.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ func (client *Client) GetSenderSignatures(ctx context.Context, count, offset int
132132
values.Add("offset", fmt.Sprintf("%d", offset))
133133

134134
err := client.doRequest(ctx, parameters{
135-
Method: "GET",
135+
Method: http.MethodGet,
136136
Path: fmt.Sprintf("senders?%s", values.Encode()),
137137
TokenType: accountToken,
138138
}, &res)

0 commit comments

Comments
 (0)