aboutsummaryrefslogtreecommitdiff
path: root/human.go
blob: d78d31f97f95e8041026626faec857b1aef06926 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package human

import (
	"encoding/json"
	"errors"
	"net/url"
	"strings"
	"time"
)

const Version = "0.1.1"

var (
	stdPorts = map[string]string{
		"http": "80", "https": "443", "gemini": "1965",
	}
)

var (
	ErrInvalidURL = errors.New("invalid url")
)

// URL represents a standard [url.URL] following normalization rules of human.json.
type URL url.URL

func (u *URL) normalize() {
	if strings.Contains(u.Host, ":") {
		sp := strings.Split(u.Host, ":")
		if v, ok := stdPorts[u.Scheme]; ok && v == sp[1] {
			u.Host = sp[0]
		}
	}
	u.Path = strings.TrimSuffix(u.Path, "/")
}

func (u *URL) UnmarshalJSON(b []byte) error {
	var s string
	err := json.Unmarshal(b, &s)
	if err != nil {
		return err
	}
	raw, err := url.Parse(s)
	if err != nil {
		return err
	}
	*u = URL(*raw)
	u.normalize()
	return nil
}

func (u *URL) MarshalJSON() ([]byte, error) {
	u.normalize()
	return json.Marshal(u.String())
}

func (u *URL) String() string {
	ur := url.URL(*u)
	return ur.String()
}

// Vouch a website to trust it.
type Vouch struct {
	URL       *URL      `json:"url"`
	VouchedAt time.Time `json:"-"`
}

func (v *Vouch) UnmarshalJSON(b []byte) error {
	type t Vouch
	var r struct {
		t
		VouchedAt string `json:"vouched_at"`
	}
	err := json.Unmarshal(b, &r)
	if err != nil {
		return err
	}
	*v = Vouch(r.t)
	v.VouchedAt, err = time.Parse(time.DateOnly, r.VouchedAt)
	return err
}

func (v *Vouch) MarshalJSON() ([]byte, error) {
	type t Vouch
	r := struct {
		t
		VouchedAt string `json:"vouched_at"`
	}{t(*v), v.VouchedAt.Format(time.DateOnly)}
	return json.Marshal(r)
}

// Human represents the human.json file.
type Human struct {
	Version string   `json:"string"`
	URL     *URL     `json:"url"`
	Vouches []*Vouch `json:"vouches"`
}