···1313// Always use [ParseCID] instead of wrapping strings directly, especially when working with network input.
1414type CID string
15151616+var cidRegex = regexp.MustCompile(`^[a-zA-Z0-9+=]{8,256}$`)
1717+1618func ParseCID(raw string) (CID, error) {
1719 if len(raw) > 256 {
1820 return "", fmt.Errorf("CID is too long (256 chars max)")
···2022 if len(raw) < 8 {
2123 return "", fmt.Errorf("CID is too short (8 chars min)")
2224 }
2323- var cidRegex = regexp.MustCompile(`^[a-zA-Z0-9+=]{8,256}$`)
2525+2426 if !cidRegex.MatchString(raw) {
2527 return "", fmt.Errorf("CID syntax didn't validate via regex")
2628 }
+5-2
atproto/syntax/datetime.go
···2121// Syntax is specified at: https://atproto.com/specs/lexicon#datetime
2222type Datetime string
23232424+var datetimeRegex = regexp.MustCompile(`^[0-9]{4}-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](.[0-9]{1,20})?(Z|([+-][0-2][0-9]:[0-5][0-9]))$`)
2525+2426func ParseDatetime(raw string) (Datetime, error) {
2527 if len(raw) > 64 {
2628 return "", fmt.Errorf("Datetime too long (max 64 chars)")
2729 }
2828- var datetimeRegex = regexp.MustCompile(`^[0-9]{4}-[01][0-9]-[0-3][0-9]T[0-2][0-9]:[0-6][0-9]:[0-6][0-9](.[0-9]{1,20})?(Z|([+-][0-2][0-9]:[0-5][0-9]))$`)
3030+2931 if !datetimeRegex.MatchString(raw) {
3032 return "", fmt.Errorf("Datetime syntax didn't validate via regex")
3133 }
···5355// Similar to ParseDatetime, but more flexible about some parsing.
5456//
5557// Note that this may mutate the internal string, so a round-trip will fail. This is intended for working with legacy/broken records, not to be used in an ongoing way.
5858+var hasTimezoneRegex = regexp.MustCompile(`^.*(([+-]\d\d:?\d\d)|[a-zA-Z])$`)
5959+5660func ParseDatetimeLenient(raw string) (Datetime, error) {
5761 // fast path: it is a valid overall datetime
5862 valid, err := ParseDatetime(raw)
···7175 }
72767377 // try adding timezone if it is missing
7474- var hasTimezoneRegex = regexp.MustCompile(`^.*(([+-]\d\d:?\d\d)|[a-zA-Z])$`)
7578 if !hasTimezoneRegex.MatchString(raw) {
7679 withTZ, err := ParseDatetime(raw + "Z")
7780 if nil == err {
+2-1
atproto/syntax/did.go
···1313// Syntax specification: https://atproto.com/specs/did
1414type DID string
15151616+var didRegex = regexp.MustCompile(`^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$`)
1717+1618func ParseDID(raw string) (DID, error) {
1719 if len(raw) > 2*1024 {
1820 return "", fmt.Errorf("DID is too long (2048 chars max)")
1921 }
2020- var didRegex = regexp.MustCompile(`^did:[a-z]+:[a-zA-Z0-9._:%-]*[a-zA-Z0-9._-]$`)
2122 if !didRegex.MatchString(raw) {
2223 return "", fmt.Errorf("DID syntax didn't validate via regex")
2324 }
+2-1
atproto/syntax/language.go
···1212// The syntax is BCP-47. This is a partial/naive parsing implementation, designed for fast validation and exact-string passthrough with no normaliztion. For actually working with BCP-47 language specifiers in atproto code bases, we recommend the golang.org/x/text/language package.
1313type Language string
14141515+var langRegex = regexp.MustCompile(`^(i|[a-z]{2,3})(-[a-zA-Z0-9]+)*$`)
1616+1517func ParseLanguage(raw string) (Language, error) {
1618 if len(raw) > 128 {
1719 return "", fmt.Errorf("Language is too long (128 chars max)")
1820 }
1919- var langRegex = regexp.MustCompile(`^(i|[a-z]{2,3})(-[a-zA-Z0-9]+)*$`)
2021 if !langRegex.MatchString(raw) {
2122 return "", fmt.Errorf("Language syntax didn't validate via regex")
2223 }
+2-1
atproto/syntax/tid.go
···2424// Syntax specification: https://atproto.com/specs/record-key
2525type TID string
26262727+var tidRegex = regexp.MustCompile(`^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$`)
2828+2729func ParseTID(raw string) (TID, error) {
2830 if len(raw) != 13 {
2931 return "", fmt.Errorf("TID is wrong length (expected 13 chars)")
3032 }
3131- var tidRegex = regexp.MustCompile(`^[234567abcdefghij][234567abcdefghijklmnopqrstuvwxyz]{12}$`)
3233 if !tidRegex.MatchString(raw) {
3334 return "", fmt.Errorf("TID syntax didn't validate via regex")
3435 }
+2-1
search/indexing.go
···4848 return nil
4949}
50505151+var tidRegex = regexp.MustCompile(`^[234567abcdefghijklmnopqrstuvwxyz]{13}$`)
5252+5153func (s *Server) indexPost(ctx context.Context, ident *identity.Identity, rec *appbsky.FeedPost, path string, rcid cid.Cid) error {
5254 ctx, span := tracer.Start(ctx, "indexPost")
5355 defer span.End()
···5658 log := s.logger.With("repo", ident.DID, "path", path, "op", "indexPost")
5759 parts := strings.SplitN(path, "/", 3)
5860 // TODO: replace with an atproto/syntax package type for TID
5959- var tidRegex = regexp.MustCompile(`^[234567abcdefghijklmnopqrstuvwxyz]{13}$`)
6061 if len(parts) != 2 || !tidRegex.MatchString(parts[1]) {
6162 log.Warn("skipping index post record with weird path/TID", "did", ident.DID, "path", path)
6263 return nil