diff --git a/atproto/syntax/handle.go b/atproto/syntax/handle.go index f1422157..15bc837b 100644 --- a/atproto/syntax/handle.go +++ b/atproto/syntax/handle.go @@ -6,6 +6,8 @@ import ( "strings" ) +var handleRegex = regexp.MustCompile(`^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$`) + // String type which represents a syntaxtually valid handle identifier, as would pass Lexicon syntax validation. // // Always use [ParseHandle] instead of wrapping strings directly, especially when working with input. @@ -17,7 +19,6 @@ func ParseHandle(raw string) (Handle, error) { if len(raw) > 253 { return "", fmt.Errorf("handle is too long (253 chars max)") } - var handleRegex = regexp.MustCompile(`^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$`) if !handleRegex.MatchString(raw) { return "", fmt.Errorf("handle syntax didn't validate via regex") } diff --git a/atproto/syntax/handle_test.go b/atproto/syntax/handle_test.go index 6f011422..5d007a8f 100644 --- a/atproto/syntax/handle_test.go +++ b/atproto/syntax/handle_test.go @@ -22,9 +22,7 @@ func TestInteropHandlesValid(t *testing.T) { } _, err := ParseHandle(line) if err != nil { - fmt.Println("GOOD: " + line) - } else { - fmt.Println("BAD: " + line) + fmt.Println("FAILED, GOOD: " + line) } assert.NoError(err) } @@ -44,7 +42,7 @@ func TestInteropHandlesInvalid(t *testing.T) { } _, err := ParseHandle(line) if err == nil { - fmt.Println("BAD: " + line) + fmt.Println("FAILED, BAD: " + line) } assert.Error(err) } diff --git a/atproto/syntax/nsid.go b/atproto/syntax/nsid.go index ec9e12b3..8865a771 100644 --- a/atproto/syntax/nsid.go +++ b/atproto/syntax/nsid.go @@ -6,6 +6,8 @@ import ( "strings" ) +var nsidRegex = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z]{0,61}[a-zA-Z])?)$`) + // String type which represents a syntaxtually valid Namespace Identifier (NSID), as would pass Lexicon syntax validation. // // Always use [ParseNSID] instead of wrapping strings directly, especially when working with input. @@ -17,7 +19,6 @@ func ParseNSID(raw string) (NSID, error) { if len(raw) > 317 { return "", fmt.Errorf("NSID is too long (317 chars max)") } - var nsidRegex = regexp.MustCompile(`^[a-zA-Z]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(\.[a-zA-Z]([a-zA-Z]{0,61}[a-zA-Z])?)$`) if !nsidRegex.MatchString(raw) { return "", fmt.Errorf("NSID syntax didn't validate via regex") } diff --git a/atproto/syntax/nsid_test.go b/atproto/syntax/nsid_test.go index c18d2f11..224bc38c 100644 --- a/atproto/syntax/nsid_test.go +++ b/atproto/syntax/nsid_test.go @@ -22,7 +22,7 @@ func TestInteropNSIDsValid(t *testing.T) { } _, err := ParseNSID(line) if err != nil { - fmt.Println("GOOD: " + line) + fmt.Println("FAILED, GOOD: " + line) } assert.NoError(err) } @@ -42,7 +42,7 @@ func TestInteropNSIDsInvalid(t *testing.T) { } _, err := ParseNSID(line) if err == nil { - fmt.Println("BAD: " + line) + fmt.Println("FAILED, BAD: " + line) } assert.Error(err) } diff --git a/atproto/syntax/recordkey.go b/atproto/syntax/recordkey.go index 5de4724a..63c0182d 100644 --- a/atproto/syntax/recordkey.go +++ b/atproto/syntax/recordkey.go @@ -5,6 +5,8 @@ import ( "regexp" ) +var recordKeyRegex = regexp.MustCompile(`^[a-zA-Z0-9_~.-]{1,512}$`) + // String type which represents a syntaxtually valid RecordKey identifier, as could be included in an AT URI // // Always use [ParseRecordKey] instead of wrapping strings directly, especially when working with input. @@ -13,19 +15,18 @@ import ( type RecordKey string func ParseRecordKey(raw string) (RecordKey, error) { - if len(raw) > 253 { + if len(raw) > 512 { return "", fmt.Errorf("recordkey is too long (512 chars max)") } if raw == "" || raw == "." || raw == ".." { return "", fmt.Errorf("recordkey can not be empty, '.', or '..'") } - var recordkeyRegex = regexp.MustCompile(`^[a-zA-Z0-9_~.-]{1,512}$`) - if !recordkeyRegex.MatchString(raw) { + if !recordKeyRegex.MatchString(raw) { return "", fmt.Errorf("recordkey syntax didn't validate via regex") } return RecordKey(raw), nil } -func (h RecordKey) String() string { - return string(h) +func (r RecordKey) String() string { + return string(r) } diff --git a/atproto/syntax/recordkey_test.go b/atproto/syntax/recordkey_test.go index f25cb36c..797ce3cf 100644 --- a/atproto/syntax/recordkey_test.go +++ b/atproto/syntax/recordkey_test.go @@ -22,9 +22,7 @@ func TestInteropRecordKeysValid(t *testing.T) { } _, err := ParseRecordKey(line) if err != nil { - fmt.Println("GOOD: " + line) - } else { - fmt.Println("FAIL: " + line) + fmt.Println("FAILED, GOOD: " + line) } assert.NoError(err) } @@ -44,7 +42,7 @@ func TestInteropRecordKeysInvalid(t *testing.T) { } _, err := ParseRecordKey(line) if err == nil { - fmt.Println("BAD: " + line) + fmt.Println("FAILED, BAD: " + line) } assert.Error(err) } diff --git a/atproto/syntax/testdata/handle_syntax_invalid.txt b/atproto/syntax/testdata/handle_syntax_invalid.txt index f824bfdc..49275a39 100644 --- a/atproto/syntax/testdata/handle_syntax_invalid.txt +++ b/atproto/syntax/testdata/handle_syntax_invalid.txt @@ -32,7 +32,11 @@ joh-.test john.-est john.tes- -# TODO: short/long examples +# max over all handle: 'shoooort' + '.loooooooooooooooooooooooooong'.repeat(9) + '.test' +shoooort.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.test + +# max segment: 'short.' + 'o'.repeat(64) + '.test' +short.oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.test # throws on "dotless" TLD handles org diff --git a/atproto/syntax/testdata/handle_syntax_valid.txt b/atproto/syntax/testdata/handle_syntax_valid.txt index 52d16fbc..a23a9213 100644 --- a/atproto/syntax/testdata/handle_syntax_valid.txt +++ b/atproto/syntax/testdata/handle_syntax_valid.txt @@ -16,7 +16,12 @@ j0.h0 jaymome-johnber123456.test jay.mome-johnber123456.test john.test.bsky.app -# TODO: short and long + +# max over all handle: 'shoooort' + '.loooooooooooooooooooooooooong'.repeat(8) + '.test' +shoooort.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.test + +# max segment: 'short.' + 'o'.repeat(63) + '.test' +short.ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.test # NOTE: this probably isn't ever going to be a real domain, but my read of the RFC is that it would be possible john.t diff --git a/atproto/syntax/testdata/recordkey_syntax_valid.txt b/atproto/syntax/testdata/recordkey_syntax_valid.txt index 4ba39689..8d77d04d 100644 --- a/atproto/syntax/testdata/recordkey_syntax_valid.txt +++ b/atproto/syntax/testdata/recordkey_syntax_valid.txt @@ -3,3 +3,6 @@ self example.com ~1.2-3_ dHJ1ZQ + +# very long: 'o'.repeat(512) +oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo