roughtime.googlesource.com/roughtime.git@v0.0.0-20201210012726-dd529367052d/go/client/main.go (about) 1 // Copyright 2016 The Roughtime Authors. 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 main 16 17 import ( 18 "encoding/json" 19 "flag" 20 "fmt" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "strings" 25 "time" 26 27 "roughtime.googlesource.com/go/client/monotime" 28 "roughtime.googlesource.com/go/config" 29 ) 30 31 var ( 32 chainFile = flag.String("chain-file", "roughtime-chain.json", "The name of a file in which the query chain will be maintained") 33 maxChainSize = flag.Int("max-chain-size", 128, "The maximum number of entries to maintain in the chain file") 34 serversFile = flag.String("servers-file", "roughtime-servers.json", "The name of a file that lists trusted Roughtime servers") 35 ) 36 37 const ( 38 // defaultServerQuorum is the default number of overlapping responses 39 // that are required to establish the current time. 40 defaultServerQuorum = 3 41 ) 42 43 func do() error { 44 flag.Parse() 45 46 serversData, err := ioutil.ReadFile(*serversFile) 47 if err != nil { 48 return err 49 } 50 51 servers, numServersSkipped, err := LoadServers(serversData) 52 if err != nil { 53 return err 54 } 55 if numServersSkipped > 0 { 56 fmt.Fprintf(os.Stderr, "Ignoring %d unsupported servers\n", numServersSkipped) 57 } 58 59 chain := &config.Chain{} 60 chainData, err := ioutil.ReadFile(*chainFile) 61 if err == nil { 62 if chain, err = LoadChain(chainData); err != nil { 63 return err 64 } 65 } else if !os.IsNotExist(err) { 66 return err 67 } 68 69 quorum := defaultServerQuorum 70 if quorum > len(servers) { 71 fmt.Fprintf(os.Stderr, "Quorum set to %d servers because not enough valid servers were found to meet the default (%d)!\n", len(servers), quorum) 72 quorum = len(servers) 73 } 74 75 var client Client 76 result, err := client.EstablishTime(chain, quorum, servers) 77 if err != nil { 78 return err 79 } 80 81 for serverName, err := range result.ServerErrors { 82 fmt.Fprintf(os.Stderr, "Failed to query %q: %s\n", serverName, err) 83 } 84 85 maxLenServerName := 0 86 for name := range result.ServerInfo { 87 if len(name) > maxLenServerName { 88 maxLenServerName = len(name) 89 } 90 } 91 92 for name, info := range result.ServerInfo { 93 fmt.Printf("%s:%s %d–%d (answered in %s)\n", name, strings.Repeat(" ", maxLenServerName-len(name)), info.Min, info.Max, info.QueryDuration) 94 } 95 96 if result.MonoUTCDelta == nil { 97 fmt.Fprintf(os.Stderr, "Failed to get %d servers to agree on the time.\n", quorum) 98 } else { 99 nowUTC := time.Unix(0, int64(monotime.Now()+*result.MonoUTCDelta)) 100 nowRealTime := time.Now() 101 102 fmt.Printf("real-time delta: %s\n", nowRealTime.Sub(nowUTC)) 103 } 104 105 // TODO: if result.OutOfRangeAnswer is set then cap the chain and 106 // upload it. 107 if result.OutOfRangeAnswer { 108 fmt.Fprintf(os.Stderr, "One or more of the answers was significantly out of range.\n") 109 } 110 111 trimChain(chain, *maxChainSize) 112 chainBytes, err := json.MarshalIndent(chain, "", " ") 113 if err != nil { 114 return err 115 } 116 117 tempFile, err := ioutil.TempFile(filepath.Dir(*chainFile), filepath.Base(*chainFile)) 118 if err != nil { 119 return err 120 } 121 defer tempFile.Close() 122 123 if _, err := tempFile.Write(chainBytes); err != nil { 124 return err 125 } 126 127 if err := os.Rename(tempFile.Name(), *chainFile); err != nil { 128 return err 129 } 130 131 return nil 132 } 133 134 func main() { 135 if err := do(); err != nil { 136 fmt.Fprintf(os.Stderr, "%s\n", err) 137 os.Exit(1) 138 } 139 }