fork of indigo with slightly nicer lexgen
at main 2.1 kB view raw
1package did 2 3import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "strings" 9 "time" 10 "unicode" 11 12 "github.com/whyrusleeping/go-did" 13 "go.opentelemetry.io/otel" 14) 15 16var webDidDefaultTimeout = 5 * time.Second 17 18type WebResolver struct { 19 Insecure bool 20 // TODO: cache? maybe at a different layer 21 22 client http.Client 23} 24 25func (wr *WebResolver) GetDocument(ctx context.Context, didstr string) (*Document, error) { 26 if wr.client.Timeout == 0 { 27 wr.client.Timeout = webDidDefaultTimeout 28 } 29 ctx, span := otel.Tracer("did").Start(ctx, "didWebGetDocument") 30 defer span.End() 31 32 pdid, err := did.ParseDID(didstr) 33 if err != nil { 34 return nil, err 35 } 36 37 val := pdid.Value() 38 if err := checkValidDidWeb(val); err != nil { 39 return nil, err 40 } 41 42 proto := "https" 43 if wr.Insecure { 44 proto = "http" 45 } 46 47 resp, err := wr.client.Get(proto + "://" + val + "/.well-known/did.json") 48 if err != nil { 49 return nil, err 50 } 51 defer resp.Body.Close() 52 53 if resp.StatusCode != 200 { 54 return nil, fmt.Errorf("fetch did request failed (status %d): %s", resp.StatusCode, resp.Status) 55 } 56 57 var out did.Document 58 if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { 59 return nil, err 60 } 61 62 return &out, nil 63} 64 65var disallowedTlds = map[string]bool{ 66 "example": true, 67 "invalid": true, 68 "local": true, 69 "arpa": true, 70 "onion": true, 71 "internal": true, 72} 73 74func (wr *WebResolver) FlushCacheFor(did string) { 75 return 76} 77 78func checkValidDidWeb(val string) error { 79 // no ports or ipv6 80 if strings.Contains(val, ":") { 81 return fmt.Errorf("did:web resolver does not handle ports or documents at sub-paths") 82 } 83 // no trailing '.' 84 if strings.HasSuffix(val, ".") { 85 return fmt.Errorf("cannot have trailing period in hostname") 86 } 87 88 parts := strings.Split(val, ".") 89 if len(parts) == 1 { 90 return fmt.Errorf("no bare hostnames (must have subdomain)") 91 } 92 93 tld := parts[len(parts)-1] 94 if disallowedTlds[tld] { 95 return fmt.Errorf("domain cannot use any disallowed TLD") 96 } 97 98 // disallow tlds that start with numbers 99 if unicode.IsNumber(rune(tld[0])) { 100 return fmt.Errorf("TLD cannot start with a number") 101 } 102 103 return nil 104}