mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 17:47:03 +00:00
Initial version of ValidateLocalPart
Does not support any quoting yet, not RFC compliant
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user