forked from
tangled.org/core
Mirror of @tangled.org/core. Running on a Raspberry Pi Zero 2 (Please be gentle).
1package hostutil
2
3import (
4 "fmt"
5 "net/url"
6 "strings"
7
8 "github.com/bluesky-social/indigo/atproto/syntax"
9)
10
11func ParseHostname(raw string) (hostname string, noSSL bool, err error) {
12 // handle case of bare hostname
13 if !strings.Contains(raw, "://") {
14 if strings.HasPrefix(raw, "localhost:") {
15 raw = "http://" + raw
16 } else {
17 raw = "https://" + raw
18 }
19 }
20
21 u, err := url.Parse(raw)
22 if err != nil {
23 return "", false, fmt.Errorf("not a valid host URL: %w", err)
24 }
25
26 switch u.Scheme {
27 case "https", "wss":
28 noSSL = false
29 case "http", "ws":
30 noSSL = true
31 default:
32 return "", false, fmt.Errorf("unsupported URL scheme: %s", u.Scheme)
33 }
34
35 // 'localhost' (exact string) is allowed *with* a required port number; SSL is optional
36 if u.Hostname() == "localhost" {
37 if u.Port() == "" || !strings.HasPrefix(u.Host, "localhost:") {
38 return "", false, fmt.Errorf("port number is required for localhost")
39 }
40 return u.Host, noSSL, nil
41 }
42
43 // port numbers not allowed otherwise
44 if u.Port() != "" {
45 return "", false, fmt.Errorf("port number not allowed for non-local names")
46 }
47
48 // check it is a real hostname (eg, not IP address or single-word alias)
49 h, err := syntax.ParseHandle(u.Host)
50 if err != nil {
51 return "", false, fmt.Errorf("not a public hostname")
52 }
53
54 // lower-case in response
55 return h.Normalize().String(), noSSL, nil
56}