1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00

Initial version of ValidateLocalPart

Does not support any quoting yet, not RFC compliant
This commit is contained in:
James Hillyerd
2013-11-03 10:25:34 -08:00
parent b2c3c4ce0f
commit ba943cb682
2 changed files with 70 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
package smtpd
import (
"bytes"
"container/list"
"crypto/sha1"
"fmt"
@@ -89,3 +90,40 @@ func ValidateDomainPart(domain string) bool {
return true
}
// ValidateLocalPart returns true if the string complies with RFC3696 recommendations
func ValidateLocalPart(local string) bool {
length := len(local)
if 1 > length || length > 64 {
// Invalid length
return false
}
if local[length-1] == '.' {
// Cannot end with a period
return false
}
prev := byte('.')
for i := 0; i < length; i++ {
c := local[i]
switch {
case ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'):
// Letters are OK
case '0' <= c && c <= '9':
// Numbers are OK
case bytes.IndexByte([]byte("!#$%&'*+-/=?^_`{|}~"), c) >= 0:
// These specials can be used unquoted
case c == '.':
// A single period is OK
if prev == '.' {
// Sequence of periods is not permitted
return false
}
default:
return false
}
prev = c
}
return true
}

View File

@@ -17,9 +17,6 @@ func TestHashMailboxName(t *testing.T) {
}
func TestValidateDomain(t *testing.T) {
assert.True(t, ValidateDomainPart("jhillyerd.github.com"),
"Simple domain failed")
assert.False(t, ValidateDomainPart(""), "Empty domain is not valid")
assert.False(t, ValidateDomainPart(strings.Repeat("a", 256)),
"Max domain length is 255")
assert.False(t, ValidateDomainPart(strings.Repeat("a", 64)+".com"),
@@ -32,6 +29,7 @@ func TestValidateDomain(t *testing.T) {
expect bool
msg string
}{
{"", false, "Empty domain is not valid"},
{"hostname", true, "Just a hostname is valid"},
{"github.com", true, "Two labels should be just fine"},
{"my-domain.com", true, "Hyphen is allowed mid-label"},
@@ -52,3 +50,34 @@ func TestValidateDomain(t *testing.T) {
}
}
}
func TestValidateLocal(t *testing.T) {
var testTable = []struct {
input string
expect bool
msg string
}{
{"", false, "Empty local is not valid"},
{"a", true, "Single letter should be fine"},
{strings.Repeat("a", 65), false, "Only valid up to 64 characters"},
{"FirstLast", true, "Mixed case permitted"},
{"user123", true, "Numbers permitted"},
{"a!#$%&'*+-/=?^_`{|}~", true, "Any of !#$%&'*+-/=?^_`{|}~ are permitted"},
{"james@mail", false, "Unquoted @ not permitted"},
{"first.last", true, "Embedded period is permitted"},
{"first..last", false, "Sequence of periods is not allowed"},
{".user", false, "Cannot lead with a period"},
{"user.", false, "Cannot end with a period"},
{"user+mailbox", true, "RFC3696 test case should be valid"},
{"customer/department=shipping", true, "RFC3696 test case should be valid"},
{"$A12345", true, "RFC3696 test case should be valid"},
{"!def!xyz%abc", true, "RFC3696 test case should be valid"},
{"_somename", true, "RFC3696 test case should be valid"},
}
for _, tt := range testTable {
if ValidateLocalPart(tt.input) != tt.expect {
t.Errorf("Expected %v for %q: %s", tt.expect, tt.input, tt.msg)
}
}
}