fork of indigo with slightly nicer lexgen
1package label
2
3import (
4 "bytes"
5 "fmt"
6
7 comatproto "github.com/bluesky-social/indigo/api/atproto"
8 "github.com/bluesky-social/indigo/atproto/crypto"
9 "github.com/bluesky-social/indigo/atproto/data"
10 "github.com/bluesky-social/indigo/atproto/syntax"
11)
12
13// version of the label data fromat implemented by this package
14const ATPROTO_LABEL_VERSION int64 = 1
15
16type Label struct {
17 CID *string `json:"cid,omitempty" cborgen:"cid,omitempty"`
18 CreatedAt string `json:"cts" cborgen:"cts"`
19 ExpiresAt *string `json:"exp,omitempty" cborgen:"exp,omitempty"`
20 Negated *bool `json:"neg,omitempty" cborgen:"neg,omitempty"`
21 SourceDID string `json:"src" cborgen:"src"`
22 URI string `json:"uri" cborgen:"uri"`
23 Val string `json:"val" cborgen:"val"`
24 Version int64 `json:"ver" cborgen:"ver"`
25 Sig data.Bytes `json:"sig,omitempty" cborgen:"sig,omitempty"`
26}
27
28// converts to map[string]any for printing as JSON
29func (l *Label) Data() map[string]any {
30 d := map[string]any{
31 "cid": l.CID,
32 "cts": l.CreatedAt,
33 "src": l.SourceDID,
34 "uri": l.URI,
35 "val": l.Val,
36 "ver": l.Version,
37 }
38 if l.CID != nil {
39 d["cid"] = l.CID
40 }
41 if l.ExpiresAt != nil {
42 d["exp"] = l.ExpiresAt
43 }
44 if l.Negated != nil {
45 d["neg"] = l.Negated
46 }
47 if l.Sig != nil {
48 d["sig"] = data.Bytes(l.Sig)
49 }
50 return d
51}
52
53// does basic checks on syntax and structure
54func (l *Label) VerifySyntax() error {
55 if l.Version != ATPROTO_LABEL_VERSION {
56 return fmt.Errorf("unsupported label version: %d", l.Version)
57 }
58 if len(l.Val) == 0 {
59 return fmt.Errorf("empty label value")
60 }
61 if l.CID != nil {
62 _, err := syntax.ParseCID(*l.CID)
63 if err != nil {
64 return fmt.Errorf("invalid label: %w", err)
65 }
66 }
67 _, err := syntax.ParseDatetime(l.CreatedAt)
68 if err != nil {
69 return fmt.Errorf("invalid label: %w", err)
70 }
71 if l.ExpiresAt != nil {
72 _, err := syntax.ParseDatetime(*l.ExpiresAt)
73 if err != nil {
74 return fmt.Errorf("invalid label: %w", err)
75 }
76 }
77 _, err = syntax.ParseDID(l.SourceDID)
78 if err != nil {
79 return fmt.Errorf("invalid label: %w", err)
80 }
81 _, err = syntax.ParseURI(l.URI)
82 if err != nil {
83 return fmt.Errorf("invalid label: %w", err)
84 }
85 return nil
86}
87
88func (l *Label) UnsignedBytes() ([]byte, error) {
89 buf := new(bytes.Buffer)
90 if l.Sig == nil {
91 if err := l.MarshalCBOR(buf); err != nil {
92 return nil, err
93 }
94 return buf.Bytes(), nil
95 }
96 unsigned := Label{
97 CID: l.CID,
98 CreatedAt: l.CreatedAt,
99 ExpiresAt: l.ExpiresAt,
100 Negated: l.Negated,
101 SourceDID: l.SourceDID,
102 URI: l.URI,
103 Val: l.Val,
104 Version: l.Version,
105 }
106 if err := unsigned.MarshalCBOR(buf); err != nil {
107 return nil, err
108 }
109 return buf.Bytes(), nil
110}
111
112// Signs the commit, storing the signature in the `Sig` field
113func (l *Label) Sign(privkey crypto.PrivateKey) error {
114 b, err := l.UnsignedBytes()
115 if err != nil {
116 return err
117 }
118 sig, err := privkey.HashAndSign(b)
119 if err != nil {
120 return err
121 }
122 l.Sig = sig
123 return nil
124}
125
126// Verifies `Sig` field using the provided key. Returns `nil` if signature is valid.
127func (l *Label) VerifySignature(pubkey crypto.PublicKey) error {
128 if l.Sig == nil {
129 return fmt.Errorf("can not verify unsigned commit")
130 }
131 b, err := l.UnsignedBytes()
132 if err != nil {
133 return err
134 }
135 return pubkey.HashAndVerify(b, l.Sig)
136}
137
138func (l *Label) ToLexicon() comatproto.LabelDefs_Label {
139 return comatproto.LabelDefs_Label{
140 Cid: l.CID,
141 Cts: l.CreatedAt,
142 Exp: l.ExpiresAt,
143 Sig: []byte(l.Sig),
144 Src: l.SourceDID,
145 Uri: l.URI,
146 Val: l.Val,
147 Ver: &l.Version,
148 }
149}
150
151func FromLexicon(l *comatproto.LabelDefs_Label) Label {
152 var v int64 = 0
153 if l.Ver != nil {
154 v = *l.Ver
155 }
156 return Label{
157 CID: l.Cid,
158 CreatedAt: l.Cts,
159 ExpiresAt: l.Exp,
160 Sig: []byte(l.Sig),
161 SourceDID: l.Src,
162 URI: l.Uri,
163 Val: l.Val,
164 Version: v,
165 }
166}