github.com/iamlotus/docker@v1.8.1/trust/trusts.go (about) 1 package trust 2 3 import ( 4 "crypto/x509" 5 "errors" 6 "io/ioutil" 7 "net/http" 8 "net/url" 9 "os" 10 "path" 11 "path/filepath" 12 "sync" 13 "time" 14 15 "github.com/Sirupsen/logrus" 16 "github.com/docker/libtrust/trustgraph" 17 ) 18 19 type TrustStore struct { 20 path string 21 caPool *x509.CertPool 22 graph trustgraph.TrustGraph 23 expiration time.Time 24 fetcher *time.Timer 25 fetchTime time.Duration 26 autofetch bool 27 httpClient *http.Client 28 baseEndpoints map[string]*url.URL 29 30 sync.RWMutex 31 } 32 33 // defaultFetchtime represents the starting duration to wait between 34 // fetching sections of the graph. Unsuccessful fetches should 35 // increase time between fetching. 36 const defaultFetchtime = 45 * time.Second 37 38 var baseEndpoints = map[string]string{"official": "https://dvjy3tqbc323p.cloudfront.net/trust/official.json"} 39 40 func NewTrustStore(path string) (*TrustStore, error) { 41 abspath, err := filepath.Abs(path) 42 if err != nil { 43 return nil, err 44 } 45 46 // Create base graph url map 47 endpoints := map[string]*url.URL{} 48 for name, endpoint := range baseEndpoints { 49 u, err := url.Parse(endpoint) 50 if err != nil { 51 return nil, err 52 } 53 endpoints[name] = u 54 } 55 56 // Load grant files 57 t := &TrustStore{ 58 path: abspath, 59 caPool: nil, 60 httpClient: &http.Client{}, 61 fetchTime: time.Millisecond, 62 baseEndpoints: endpoints, 63 } 64 65 if err := t.reload(); err != nil { 66 return nil, err 67 } 68 69 return t, nil 70 } 71 72 func (t *TrustStore) reload() error { 73 t.Lock() 74 defer t.Unlock() 75 76 matches, err := filepath.Glob(filepath.Join(t.path, "*.json")) 77 if err != nil { 78 return err 79 } 80 statements := make([]*trustgraph.Statement, len(matches)) 81 for i, match := range matches { 82 f, err := os.Open(match) 83 if err != nil { 84 return err 85 } 86 statements[i], err = trustgraph.LoadStatement(f, nil) 87 if err != nil { 88 f.Close() 89 return err 90 } 91 f.Close() 92 } 93 if len(statements) == 0 { 94 if t.autofetch { 95 logrus.Debugf("No grants, fetching") 96 t.fetcher = time.AfterFunc(t.fetchTime, t.fetch) 97 } 98 return nil 99 } 100 101 grants, expiration, err := trustgraph.CollapseStatements(statements, true) 102 if err != nil { 103 return err 104 } 105 106 t.expiration = expiration 107 t.graph = trustgraph.NewMemoryGraph(grants) 108 logrus.Debugf("Reloaded graph with %d grants expiring at %s", len(grants), expiration) 109 110 if t.autofetch { 111 nextFetch := expiration.Sub(time.Now()) 112 if nextFetch < 0 { 113 nextFetch = defaultFetchtime 114 } else { 115 nextFetch = time.Duration(0.8 * (float64)(nextFetch)) 116 } 117 t.fetcher = time.AfterFunc(nextFetch, t.fetch) 118 } 119 120 return nil 121 } 122 123 func (t *TrustStore) fetchBaseGraph(u *url.URL) (*trustgraph.Statement, error) { 124 req := &http.Request{ 125 Method: "GET", 126 URL: u, 127 Proto: "HTTP/1.1", 128 ProtoMajor: 1, 129 ProtoMinor: 1, 130 Header: make(http.Header), 131 Body: nil, 132 Host: u.Host, 133 } 134 135 resp, err := t.httpClient.Do(req) 136 if err != nil { 137 return nil, err 138 } 139 if resp.StatusCode == 404 { 140 return nil, errors.New("base graph does not exist") 141 } 142 143 defer resp.Body.Close() 144 145 return trustgraph.LoadStatement(resp.Body, t.caPool) 146 } 147 148 // fetch retrieves updated base graphs. This function cannot error, it 149 // should only log errors 150 func (t *TrustStore) fetch() { 151 t.Lock() 152 defer t.Unlock() 153 154 if t.autofetch && t.fetcher == nil { 155 // Do nothing ?? 156 return 157 } 158 159 fetchCount := 0 160 for bg, ep := range t.baseEndpoints { 161 statement, err := t.fetchBaseGraph(ep) 162 if err != nil { 163 logrus.Infof("Trust graph fetch failed: %s", err) 164 continue 165 } 166 b, err := statement.Bytes() 167 if err != nil { 168 logrus.Infof("Bad trust graph statement: %s", err) 169 continue 170 } 171 // TODO check if value differs 172 if err := ioutil.WriteFile(path.Join(t.path, bg+".json"), b, 0600); err != nil { 173 logrus.Infof("Error writing trust graph statement: %s", err) 174 } 175 fetchCount++ 176 } 177 logrus.Debugf("Fetched %d base graphs at %s", fetchCount, time.Now()) 178 179 if fetchCount > 0 { 180 go func() { 181 if err := t.reload(); err != nil { 182 logrus.Infof("Reload of trust graph failed: %s", err) 183 } 184 }() 185 t.fetchTime = defaultFetchtime 186 t.fetcher = nil 187 } else if t.autofetch { 188 maxTime := 10 * defaultFetchtime 189 t.fetchTime = time.Duration(1.5 * (float64)(t.fetchTime+time.Second)) 190 if t.fetchTime > maxTime { 191 t.fetchTime = maxTime 192 } 193 t.fetcher = time.AfterFunc(t.fetchTime, t.fetch) 194 } 195 }