+2
-1
atproto/syntax/handle.go
+2
-1
atproto/syntax/handle.go
···
6
6
"strings"
7
7
)
8
8
9
+
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])?$`)
10
+
9
11
// String type which represents a syntaxtually valid handle identifier, as would pass Lexicon syntax validation.
10
12
//
11
13
// Always use [ParseHandle] instead of wrapping strings directly, especially when working with input.
···
17
19
if len(raw) > 253 {
18
20
return "", fmt.Errorf("handle is too long (253 chars max)")
19
21
}
20
-
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])?$`)
21
22
if !handleRegex.MatchString(raw) {
22
23
return "", fmt.Errorf("handle syntax didn't validate via regex")
23
24
}
+2
-4
atproto/syntax/handle_test.go
+2
-4
atproto/syntax/handle_test.go
···
22
22
}
23
23
_, err := ParseHandle(line)
24
24
if err != nil {
25
-
fmt.Println("GOOD: " + line)
26
-
} else {
27
-
fmt.Println("BAD: " + line)
25
+
fmt.Println("FAILED, GOOD: " + line)
28
26
}
29
27
assert.NoError(err)
30
28
}
···
44
42
}
45
43
_, err := ParseHandle(line)
46
44
if err == nil {
47
-
fmt.Println("BAD: " + line)
45
+
fmt.Println("FAILED, BAD: " + line)
48
46
}
49
47
assert.Error(err)
50
48
}
+2
-1
atproto/syntax/nsid.go
+2
-1
atproto/syntax/nsid.go
···
6
6
"strings"
7
7
)
8
8
9
+
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])?)$`)
10
+
9
11
// String type which represents a syntaxtually valid Namespace Identifier (NSID), as would pass Lexicon syntax validation.
10
12
//
11
13
// Always use [ParseNSID] instead of wrapping strings directly, especially when working with input.
···
17
19
if len(raw) > 317 {
18
20
return "", fmt.Errorf("NSID is too long (317 chars max)")
19
21
}
20
-
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])?)$`)
21
22
if !nsidRegex.MatchString(raw) {
22
23
return "", fmt.Errorf("NSID syntax didn't validate via regex")
23
24
}
+2
-2
atproto/syntax/nsid_test.go
+2
-2
atproto/syntax/nsid_test.go
···
22
22
}
23
23
_, err := ParseNSID(line)
24
24
if err != nil {
25
-
fmt.Println("GOOD: " + line)
25
+
fmt.Println("FAILED, GOOD: " + line)
26
26
}
27
27
assert.NoError(err)
28
28
}
···
42
42
}
43
43
_, err := ParseNSID(line)
44
44
if err == nil {
45
-
fmt.Println("BAD: " + line)
45
+
fmt.Println("FAILED, BAD: " + line)
46
46
}
47
47
assert.Error(err)
48
48
}
+6
-5
atproto/syntax/recordkey.go
+6
-5
atproto/syntax/recordkey.go
···
5
5
"regexp"
6
6
)
7
7
8
+
var recordKeyRegex = regexp.MustCompile(`^[a-zA-Z0-9_~.-]{1,512}$`)
9
+
8
10
// String type which represents a syntaxtually valid RecordKey identifier, as could be included in an AT URI
9
11
//
10
12
// Always use [ParseRecordKey] instead of wrapping strings directly, especially when working with input.
···
13
15
type RecordKey string
14
16
15
17
func ParseRecordKey(raw string) (RecordKey, error) {
16
-
if len(raw) > 253 {
18
+
if len(raw) > 512 {
17
19
return "", fmt.Errorf("recordkey is too long (512 chars max)")
18
20
}
19
21
if raw == "" || raw == "." || raw == ".." {
20
22
return "", fmt.Errorf("recordkey can not be empty, '.', or '..'")
21
23
}
22
-
var recordkeyRegex = regexp.MustCompile(`^[a-zA-Z0-9_~.-]{1,512}$`)
23
-
if !recordkeyRegex.MatchString(raw) {
24
+
if !recordKeyRegex.MatchString(raw) {
24
25
return "", fmt.Errorf("recordkey syntax didn't validate via regex")
25
26
}
26
27
return RecordKey(raw), nil
27
28
}
28
29
29
-
func (h RecordKey) String() string {
30
-
return string(h)
30
+
func (r RecordKey) String() string {
31
+
return string(r)
31
32
}
+2
-4
atproto/syntax/recordkey_test.go
+2
-4
atproto/syntax/recordkey_test.go
···
22
22
}
23
23
_, err := ParseRecordKey(line)
24
24
if err != nil {
25
-
fmt.Println("GOOD: " + line)
26
-
} else {
27
-
fmt.Println("FAIL: " + line)
25
+
fmt.Println("FAILED, GOOD: " + line)
28
26
}
29
27
assert.NoError(err)
30
28
}
···
44
42
}
45
43
_, err := ParseRecordKey(line)
46
44
if err == nil {
47
-
fmt.Println("BAD: " + line)
45
+
fmt.Println("FAILED, BAD: " + line)
48
46
}
49
47
assert.Error(err)
50
48
}
+5
-1
atproto/syntax/testdata/handle_syntax_invalid.txt
+5
-1
atproto/syntax/testdata/handle_syntax_invalid.txt
···
32
32
john.-est
33
33
john.tes-
34
34
35
-
# TODO: short/long examples
35
+
# max over all handle: 'shoooort' + '.loooooooooooooooooooooooooong'.repeat(9) + '.test'
36
+
shoooort.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.test
37
+
38
+
# max segment: 'short.' + 'o'.repeat(64) + '.test'
39
+
short.oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.test
36
40
37
41
# throws on "dotless" TLD handles
38
42
org
+6
-1
atproto/syntax/testdata/handle_syntax_valid.txt
+6
-1
atproto/syntax/testdata/handle_syntax_valid.txt
···
16
16
jaymome-johnber123456.test
17
17
jay.mome-johnber123456.test
18
18
john.test.bsky.app
19
-
# TODO: short and long
19
+
20
+
# max over all handle: 'shoooort' + '.loooooooooooooooooooooooooong'.repeat(8) + '.test'
21
+
shoooort.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.loooooooooooooooooooooooooong.test
22
+
23
+
# max segment: 'short.' + 'o'.repeat(63) + '.test'
24
+
short.ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.test
20
25
21
26
# NOTE: this probably isn't ever going to be a real domain, but my read of the RFC is that it would be possible
22
27
john.t
+3
atproto/syntax/testdata/recordkey_syntax_valid.txt
+3
atproto/syntax/testdata/recordkey_syntax_valid.txt
···
3
3
example.com
4
4
~1.2-3_
5
5
dHJ1ZQ
6
+
7
+
# very long: 'o'.repeat(512)
8
+
oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo