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 }