-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(GODT-2638): Validate if messages adhere to rfc5322 header rules
See `rfc5322.ValidateMessageHeaderFields`'s comments for more info.
- Loading branch information
1 parent
633e61c
commit 75fd429
Showing
28 changed files
with
391 additions
and
192 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package rfc5322 | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"github.com/ProtonMail/gluon/rfc822" | ||
) | ||
|
||
var ErrInvalidMessage = errors.New("invalid rfc5322 message") | ||
|
||
// ValidateMessageHeaderFields checks the headers of message to verify that: | ||
// * From and Date are present. | ||
// * If From has multiple addresses, a Sender field must be present. | ||
// * If Both From and Sender are present and they contain one address, they must not be equal. | ||
func ValidateMessageHeaderFields(literal []byte) error { | ||
headerBytes, _ := rfc822.Split(literal) | ||
|
||
header, err := rfc822.NewHeader(headerBytes) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Check for date. | ||
{ | ||
value := header.Get("Date") | ||
if len(value) == 0 { | ||
return fmt.Errorf("%w: Required header field 'Date' not found or empty", ErrInvalidMessage) | ||
} | ||
} | ||
|
||
// Check for from. | ||
{ | ||
value := header.Get("From") | ||
if len(value) == 0 { | ||
return fmt.Errorf("%w: Required header field 'From' not found or empty", ErrInvalidMessage) | ||
} | ||
|
||
// Check if From is a multi address. If so, a sender filed must be present and non-empty. | ||
addresses, err := ParseAddressList(value) | ||
if err != nil { | ||
return fmt.Errorf("%w: failed to parse From header: %v", ErrInvalidMessage, err) | ||
} | ||
|
||
if len(addresses) > 1 { | ||
senderValue := header.Get("Sender") | ||
if len(senderValue) == 0 { | ||
return fmt.Errorf("%w: Required header field 'Sender' not found or empty", ErrInvalidMessage) | ||
} | ||
_, err := ParseAddress(senderValue) | ||
if err != nil { | ||
return fmt.Errorf("%w: failed to parse Sender header: %v", ErrInvalidMessage, err) | ||
} | ||
} else { | ||
senderValue, ok := header.GetChecked("Sender") | ||
if ok { | ||
if len(senderValue) == 0 { | ||
return fmt.Errorf("%w: Required header field 'Sender' should not be empty", ErrInvalidMessage) | ||
} | ||
|
||
senderAddr, err := ParseAddress(senderValue) | ||
if err != nil { | ||
return fmt.Errorf("%w: failed to parse Sender header: %v", ErrInvalidMessage, err) | ||
} | ||
|
||
if len(senderAddr) == 1 && senderAddr[0].Address == addresses[0].Address { | ||
return fmt.Errorf("%w: `Sender` should not be present if equal to `From`", ErrInvalidMessage) | ||
} | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package rfc5322 | ||
|
||
import ( | ||
"github.com/stretchr/testify/require" | ||
"testing" | ||
) | ||
|
||
func TestValidateMessageHeaderFields_RequiredFieldsPass(t *testing.T) { | ||
const literal = `From: Foo@bar.com | ||
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) | ||
` | ||
|
||
require.NoError(t, ValidateMessageHeaderFields([]byte(literal))) | ||
} | ||
|
||
func TestValidateMessageHeaderFields_ErrOnMissingFrom(t *testing.T) { | ||
const literal = `Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) | ||
` | ||
|
||
require.Error(t, ValidateMessageHeaderFields([]byte(literal))) | ||
} | ||
|
||
func TestValidateMessageHeaderFields_ErrOnMissingDate(t *testing.T) { | ||
const literal = `From: Foo@bar.com | ||
` | ||
|
||
require.Error(t, ValidateMessageHeaderFields([]byte(literal))) | ||
} | ||
|
||
func TestValidateMessageHeaderFields_ErrOnSingleFromAndSenderEqual(t *testing.T) { | ||
const literal = `From: Foo@bar.com | ||
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) | ||
Sender: Foo@bar.com | ||
` | ||
|
||
require.Error(t, ValidateMessageHeaderFields([]byte(literal))) | ||
} | ||
|
||
func TestValidateMessageHeaderFields_AllowSingleFromWithDifferentSender(t *testing.T) { | ||
const literal = `From: Foo@bar.com | ||
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) | ||
Sender: Bar@bar.com | ||
` | ||
|
||
require.NoError(t, ValidateMessageHeaderFields([]byte(literal))) | ||
} | ||
|
||
func TestValidateMessageHeaderFields_ErrOnMultipleFromAndNoSender(t *testing.T) { | ||
const literal = `From: Foo@bar.com, Bar@bar.com | ||
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) | ||
` | ||
|
||
require.Error(t, ValidateMessageHeaderFields([]byte(literal))) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.