github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/binary_transparency/firmware/cmd/ft_personality/impl/ft_personality.go (about)

     1  // Copyright 2020 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package impl is the implementation of the Firmware Transparency personality server.
    16  // This requires a Trillian instance to be reachable via gRPC and a tree to have
    17  // been provisioned.
    18  package impl
    19  
    20  import (
    21  	"context"
    22  	"database/sql"
    23  	"errors"
    24  	"fmt"
    25  	"net/http"
    26  	"time"
    27  
    28  	"github.com/golang/glog"
    29  	"github.com/google/trillian-examples/binary_transparency/firmware/cmd/ft_personality/internal/cas"
    30  	ih "github.com/google/trillian-examples/binary_transparency/firmware/cmd/ft_personality/internal/http"
    31  	"github.com/google/trillian-examples/binary_transparency/firmware/cmd/ft_personality/internal/trees"
    32  	"github.com/google/trillian-examples/binary_transparency/firmware/cmd/ft_personality/internal/trillian"
    33  	"github.com/gorilla/mux"
    34  	"golang.org/x/mod/sumdb/note"
    35  
    36  	_ "github.com/mattn/go-sqlite3" // Load drivers for sqlite3
    37  )
    38  
    39  // PersonalityOpts encapsulates options for running an FT personality.
    40  type PersonalityOpts struct {
    41  	ListenAddr     string
    42  	CASFile        string
    43  	TrillianAddr   string
    44  	ConnectTimeout time.Duration
    45  	STHRefresh     time.Duration
    46  	Signer         note.Signer
    47  }
    48  
    49  // Main runs the FT personality server until the context is canceled.
    50  func Main(ctx context.Context, opts PersonalityOpts) error {
    51  	if len(opts.CASFile) == 0 {
    52  		return errors.New("CAS file is required")
    53  	}
    54  
    55  	glog.Infof("Connecting to local DB at %q", opts.CASFile)
    56  	db, err := sql.Open("sqlite3", opts.CASFile)
    57  	if err != nil {
    58  		return fmt.Errorf("failed to connect to DB: %w", err)
    59  	}
    60  	cas, err := cas.NewBinaryStorage(db)
    61  	if err != nil {
    62  		return fmt.Errorf("failed to connect CAS to DB: %w", err)
    63  	}
    64  
    65  	// TODO(mhutchinson): This is putting the tree config in the CAS DB.
    66  	// This isn't unreasonable, but it does make the naming misleading now.
    67  	treeStorage := trees.NewTreeStorage(db)
    68  
    69  	glog.Infof("Connecting to Trillian Log...")
    70  	tclient, err := trillian.NewClient(ctx, opts.ConnectTimeout, opts.TrillianAddr, treeStorage)
    71  	if err != nil {
    72  		return fmt.Errorf("failed to connect to Trillian: %w", err)
    73  	}
    74  	defer tclient.Close()
    75  
    76  	// Periodically sync the golden STH in the background.
    77  	go func() {
    78  		for ctx.Err() == nil {
    79  			if err := tclient.UpdateRoot(ctx); err != nil {
    80  				glog.Warningf("error updating STH: %v", err)
    81  			}
    82  
    83  			select {
    84  			case <-ctx.Done():
    85  			case <-time.After(opts.STHRefresh):
    86  			}
    87  		}
    88  	}()
    89  
    90  	glog.Infof("Starting FT personality server...")
    91  	srv := ih.NewServer(tclient, cas, opts.Signer)
    92  	r := mux.NewRouter()
    93  	srv.RegisterHandlers(r)
    94  	hServer := &http.Server{
    95  		Addr:    opts.ListenAddr,
    96  		Handler: r,
    97  	}
    98  	e := make(chan error, 1)
    99  	go func() {
   100  		e <- hServer.ListenAndServe()
   101  		close(e)
   102  	}()
   103  	<-ctx.Done()
   104  	glog.Info("Server shutting down")
   105  	if err := hServer.Shutdown(ctx); err != nil {
   106  		glog.Errorf("server.Shutdown(): %v", err)
   107  	}
   108  	return <-e
   109  }