porting all github actions from bluesky-social/indigo to tangled CI
at main 2.8 kB view raw
1package repo 2 3import ( 4 "bytes" 5 "fmt" 6 7 "github.com/bluesky-social/indigo/atproto/crypto" 8 "github.com/bluesky-social/indigo/atproto/data" 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 11 "github.com/ipfs/go-cid" 12) 13 14// atproto repo commit object as a struct type. Can be used for direct CBOR or JSON serialization. 15type Commit struct { 16 DID string `json:"did" cborgen:"did"` 17 Version int64 `json:"version" cborgen:"version"` // currently: 3 18 Prev *cid.Cid `json:"prev" cborgen:"prev"` // NOTE: omitempty would break signature verification for repo v3 19 Data cid.Cid `json:"data" cborgen:"data"` 20 Sig []byte `json:"sig,omitempty" cborgen:"sig,omitempty"` 21 Rev string `json:"rev,omitempty" cborgen:"rev,omitempty"` 22} 23 24// does basic checks that field values and syntax are correct 25func (c *Commit) VerifyStructure() error { 26 if c.Version != ATPROTO_REPO_VERSION { 27 return fmt.Errorf("unsupported repo version: %d", c.Version) 28 } 29 if len(c.Sig) == 0 { 30 return fmt.Errorf("empty commit signature") 31 } 32 _, err := syntax.ParseDID(c.DID) 33 if err != nil { 34 return fmt.Errorf("invalid commit data: %w", err) 35 } 36 _, err = syntax.ParseTID(c.Rev) 37 if err != nil { 38 return fmt.Errorf("invalid commit data: %w", err) 39 } 40 return nil 41} 42 43// returns a representation of the commit object as atproto data (eg, for JSON serialization) 44func (c *Commit) AsData() map[string]any { 45 d := map[string]any{ 46 "did": c.DID, 47 "version": c.Version, 48 "prev": (*data.CIDLink)(c.Prev), 49 "data": data.CIDLink(c.Data), 50 } 51 if c.Sig != nil { 52 d["sig"] = data.Bytes(c.Sig) 53 } 54 if c.Rev != "" { 55 d["rev"] = c.Rev 56 } 57 return d 58} 59 60// Encodes the commit object as DAG-CBOR, without the signature field. Used for signing or validating signatures. 61func (c *Commit) UnsignedBytes() ([]byte, error) { 62 buf := new(bytes.Buffer) 63 if c.Sig == nil { 64 if err := c.MarshalCBOR(buf); err != nil { 65 return nil, err 66 } 67 return buf.Bytes(), nil 68 } 69 unsigned := Commit{ 70 DID: c.DID, 71 Version: c.Version, 72 Prev: c.Prev, 73 Data: c.Data, 74 Rev: c.Rev, 75 } 76 if err := unsigned.MarshalCBOR(buf); err != nil { 77 return nil, err 78 } 79 return buf.Bytes(), nil 80} 81 82// Signs the commit, storing the signature in the `Sig` field 83func (c *Commit) Sign(privkey crypto.PrivateKey) error { 84 b, err := c.UnsignedBytes() 85 if err != nil { 86 return err 87 } 88 sig, err := privkey.HashAndSign(b) 89 if err != nil { 90 return err 91 } 92 c.Sig = sig 93 return nil 94} 95 96// Verifies `Sig` field using the provided key. Returns `nil` if signature is valid. 97func (c *Commit) VerifySignature(pubkey crypto.PublicKey) error { 98 if c.Sig == nil { 99 return fmt.Errorf("can not verify unsigned commit") 100 } 101 b, err := c.UnsignedBytes() 102 if err != nil { 103 return err 104 } 105 return pubkey.HashAndVerify(b, c.Sig) 106}