blob: 69b35cadfa15cfeb5938e2ad9f3f192336819714 [file] [log] [blame]
// 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 pmhttp
import (
"encoding/json"
"errors"
"fmt"
"log"
"math"
"net/http"
"os"
tuf_data "github.com/theupdateframework/go-tuf/data"
"go.fuchsia.dev/fuchsia/src/sys/pkg/lib/repo"
)
var (
OutOfRangeError = errors.New("out of range error")
)
type ConfigServer struct {
rootKeyFetcher func() []byte
encryptionKey string
}
func NewConfigServer(rootKeyFetcher func() []byte, encryptionKey string) *ConfigServer {
return &ConfigServer{rootKeyFetcher: rootKeyFetcher, encryptionKey: encryptionKey}
}
type Config struct {
ID string
RepoURL string
BlobRepoURL string
RatePeriod int
RootKeys []repo.KeyConfig
RootVersion uint32 `json:"rootVersion,omitempty"`
RootThreshold uint32 `json:"rootThreshold,omitempty"`
StatusConfig struct {
Enabled bool
}
Auto bool
BlobKey *struct {
Data [32]uint8
}
}
func (c *ConfigServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var scheme = "http://"
if r.TLS != nil {
scheme = "https://"
}
repoUrl := fmt.Sprintf("%s%s", scheme, r.Host)
cfg, err := c.parseConfig(repoUrl)
if err != nil {
log.Printf("%s", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(cfg)
}
func (c *ConfigServer) parseConfig(repoUrl string) (Config, error) {
cfg := Config{
ID: repoUrl,
RepoURL: repoUrl,
BlobRepoURL: repoUrl + "/blobs",
RatePeriod: 60,
StatusConfig: struct {
Enabled bool
}{
Enabled: true,
},
Auto: true,
}
if c.encryptionKey != "" {
keyBytes, err := os.ReadFile(c.encryptionKey)
if err != nil {
log.Fatal(err)
}
if len(keyBytes) != 32 {
log.Fatalf("encryption key %s of improper size", c.encryptionKey)
}
cfg.BlobKey = &struct{ Data [32]uint8 }{}
copy(cfg.BlobKey.Data[:], keyBytes)
}
root, err := func() (tuf_data.Root, error) {
var signed tuf_data.Signed
var root tuf_data.Root
if err := json.Unmarshal(c.rootKeyFetcher(), &signed); err != nil {
return root, err
}
if err := json.Unmarshal(signed.Signed, &root); err != nil {
return root, err
}
return root, nil
}()
if err != nil {
return Config{}, fmt.Errorf("root.json parsing error: %w", err)
}
cfg.RootKeys, err = repo.GetRootKeys(&root)
if err != nil {
return Config{}, fmt.Errorf("could not get root keys from root.json: %w", err)
}
cfg.RootVersion, err = intToUint32(root.Version)
if err != nil {
return Config{}, fmt.Errorf("error parsing root version: %w", err)
}
if rootRole, ok := root.Roles["root"]; ok {
cfg.RootThreshold, err = intToUint32(rootRole.Threshold)
if err != nil {
return Config{}, fmt.Errorf("error parsing root threshold: %w", err)
}
}
return cfg, nil
}
func intToUint32(x int) (uint32, error) {
if x < 0 || x > math.MaxUint32 {
return 0, OutOfRangeError
}
return uint32(x), nil
}