tinyrelayfile
tinyrelay/internal/catalog/validate.go/

internal/catalog/validate.go raw
1package catalog
2
3import (
4 "database/sql"
5 "encoding/hex"
6 "errors"
7 "fmt"
8 "net"
9 "net/url"
10 "regexp"
11 "strings"
12)
13
14var labelPattern = regexp.MustCompile(`^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$`)
15
16func normalizeName(name string) (string, error) {
17 name = strings.TrimSpace(name)
18 if name == "" || len(name) > 128 || strings.ContainsAny(name, "/\\") || hasControl(name) {
19 return "", errors.New("tenant name must be non-empty, safe, and at most 128 characters")
20 }
21 return name, nil
22}
23
24func normalizeOwner(owner string) (string, error) {
25 if len(owner) != 64 || owner != strings.ToLower(owner) {
26 return "", errors.New("owner must be a lowercase 32-byte hex public key")
27 }
28 decoded, err := hex.DecodeString(owner)
29 if err != nil || len(decoded) != 32 {
30 return "", errors.New("owner must be a lowercase 32-byte hex public key")
31 }
32 return owner, nil
33}
34
35func normalizeTemplate(template string) (string, error) {
36 template = strings.TrimSpace(template)
37 if template == "" {
38 return "default", nil
39 }
40 if len(template) > 64 || strings.ContainsAny(template, "/\\") || hasControl(template) {
41 return "", errors.New("tenant template must be safe and at most 64 characters")
42 }
43 return template, nil
44}
45
46func normalizeSource(source string) (string, error) {
47 source = strings.TrimSpace(source)
48 if source == "" {
49 return "", nil
50 }
51 u, err := url.Parse(source)
52 if err != nil || u.Host == "" || (u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "ws" && u.Scheme != "wss") || u.User != nil {
53 return "", errors.New("source must be an http, https, ws, or wss relay URL")
54 }
55 return source, nil
56}
57
58func normalizeHost(host string) (string, error) {
59 host = strings.TrimSuffix(strings.ToLower(strings.TrimSpace(host)), ".")
60 if host == "" || len(host) > 253 || strings.ContainsAny(host, "/\\:@?#") || hasControl(host) {
61 return "", errors.New("hostname must be a normalized DNS name")
62 }
63 if net.ParseIP(host) != nil {
64 return host, nil
65 }
66 for _, label := range strings.Split(host, ".") {
67 if !labelPattern.MatchString(label) {
68 return "", fmt.Errorf("invalid hostname label %q", label)
69 }
70 }
71 return host, nil
72}
73
74func hasControl(value string) bool {
75 for _, r := range value {
76 if r < 0x20 || r == 0x7f {
77 return true
78 }
79 }
80 return false
81}
82
83func isConstraint(err error) bool {
84 return strings.Contains(strings.ToLower(err.Error()), "constraint") || errors.Is(err, sql.ErrNoRows)
85}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs