|  | // Copyright 2019 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | package repo | 
|  |  | 
|  | import ( | 
|  | "encoding/json" | 
|  | "fmt" | 
|  |  | 
|  | tuf_data "github.com/flynn/go-tuf/data" | 
|  | ) | 
|  |  | 
|  | // Config is a struct that mirrors an associated FIDL table | 
|  | // definition in //sdk/fidl/fuchsia.pkg/repo.fidl. Documentation is as in | 
|  | // that file. Ditto for the types that comprise its definition. | 
|  | // | 
|  | // Keep these in sync with their repo.fidl counterparts as well as the custom | 
|  | // | 
|  | type Config struct { | 
|  | URL              string         `json:"repo_url"` | 
|  | RootKeys         []KeyConfig    `json:"root_keys"` | 
|  | Mirrors          []MirrorConfig `json:"mirrors"` | 
|  | RootVersion      uint32         `json:"root_version"` | 
|  | RootThreshold    uint32         `json:"root_threshold"` | 
|  | UpdatePackageURL string         `json:"update_package_url,omitempty"` | 
|  | } | 
|  |  | 
|  | type MirrorConfig struct { | 
|  | URL       string `json:"mirror_url"` | 
|  | Subscribe bool   `json:"subscribe"` | 
|  | BlobURL   string `json:"blob_mirror_url,omitempty"` | 
|  | } | 
|  |  | 
|  | type KeyConfig struct { | 
|  | // ED25519Key is a 32-byte, lowercase, hex-encoded key. | 
|  | ED25519Key string | 
|  | } | 
|  |  | 
|  | // We replicate the serialization/deserialization logic given in | 
|  | // //src/sys/pkg/lib/fidl-fuchsia-pkg-ext/src/repo.rs; | 
|  | // Per this logic, we set the BlobURL field in MirrorConfig as omitempty (above), | 
|  | // and give custom marshaling logic to the key config. | 
|  | // | 
|  |  | 
|  | // This alias allows to make use of the default (un)marshalling logic of Config as we redefine it. | 
|  | type config Config | 
|  |  | 
|  | func (cfg *Config) MarshalJSON() ([]byte, error) { | 
|  | cfg2 := config(*cfg) | 
|  | if cfg2.RootVersion == 0 { | 
|  | cfg2.RootVersion = 1 | 
|  | } | 
|  | if cfg2.RootThreshold == 0 { | 
|  | cfg2.RootThreshold = 1 | 
|  | } | 
|  | return json.Marshal(&cfg2) | 
|  | } | 
|  |  | 
|  | func (cfg *Config) UnmarshalJSON(data []byte) error { | 
|  | var cfg2 config | 
|  | if err := json.Unmarshal(data, &cfg2); err != nil { | 
|  | return err | 
|  | } | 
|  | if cfg2.RootVersion == 0 { | 
|  | cfg2.RootVersion = 1 | 
|  | } | 
|  | if cfg2.RootThreshold == 0 { | 
|  | cfg2.RootThreshold = 1 | 
|  | } | 
|  | *cfg = Config(cfg2) | 
|  | return nil | 
|  | } | 
|  |  | 
|  | type typeAndValue struct { | 
|  | Type  string `json:"type"` | 
|  | Value string `json:"value"` | 
|  | } | 
|  |  | 
|  | func (key *KeyConfig) MarshalJSON() ([]byte, error) { | 
|  | return json.Marshal(&typeAndValue{ | 
|  | Type:  tuf_data.KeyTypeEd25519, | 
|  | Value: key.ED25519Key, | 
|  | }) | 
|  | } | 
|  |  | 
|  | func (key *KeyConfig) UnmarshalJSON(data []byte) error { | 
|  | var tv typeAndValue | 
|  | if err := json.Unmarshal(data, &tv); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | switch tv.Type { | 
|  | case tuf_data.KeyTypeEd25519: | 
|  | key.ED25519Key = tv.Value | 
|  | return nil | 
|  | default: | 
|  | return fmt.Errorf("unexpected key type: %q", tv.Type) | 
|  | } | 
|  | } | 
|  |  | 
|  | // GetRootKeys returns the list of public key config objects as read from the | 
|  | // contents of a repository's root metadata file. | 
|  | func GetRootKeys(root *tuf_data.Root) ([]KeyConfig, error) { | 
|  | var rootKeys []KeyConfig | 
|  | for _, k := range root.UniqueKeys()["root"] { | 
|  | v := k.Value.Public.String() | 
|  | var key KeyConfig | 
|  | switch k.Type { | 
|  | case tuf_data.KeyTypeEd25519: | 
|  | key.ED25519Key = v | 
|  | default: | 
|  | return nil, fmt.Errorf("unexpected key type: %q", k.Type) | 
|  | } | 
|  | rootKeys = append(rootKeys, key) | 
|  | } | 
|  | return rootKeys, nil | 
|  | } |