github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/asserts/fetcher.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package asserts 21 22 import ( 23 "fmt" 24 ) 25 26 type fetchProgress int 27 28 const ( 29 fetchNotSeen fetchProgress = iota 30 fetchRetrieved 31 fetchSaved 32 ) 33 34 // A Fetcher helps fetching assertions and their prerequisites. 35 type Fetcher interface { 36 // Fetch retrieves the assertion indicated by ref then its prerequisites 37 // recursively, along the way saving prerequisites before dependent assertions. 38 Fetch(*Ref) error 39 // Save retrieves the prerequisites of the assertion recursively, 40 // along the way saving them, and finally saves the assertion. 41 Save(Assertion) error 42 } 43 44 type fetcher struct { 45 db RODatabase 46 retrieve func(*Ref) (Assertion, error) 47 save func(Assertion) error 48 49 fetched map[string]fetchProgress 50 } 51 52 // NewFetcher creates a Fetcher which will use trustedDB to determine trusted assertions, will fetch assertions following prerequisites using retrieve, and then will pass them to save, saving prerequisites before dependent assertions. 53 func NewFetcher(trustedDB RODatabase, retrieve func(*Ref) (Assertion, error), save func(Assertion) error) Fetcher { 54 return &fetcher{ 55 db: trustedDB, 56 retrieve: retrieve, 57 save: save, 58 fetched: make(map[string]fetchProgress), 59 } 60 } 61 62 func (f *fetcher) chase(ref *Ref, a Assertion) error { 63 // check if ref points to predefined assertion, in which case 64 // there is nothing to do 65 _, err := ref.Resolve(f.db.FindPredefined) 66 if err == nil { 67 return nil 68 } 69 if !IsNotFound(err) { 70 return err 71 } 72 u := ref.Unique() 73 switch f.fetched[u] { 74 case fetchSaved: 75 return nil // nothing to do 76 case fetchRetrieved: 77 return fmt.Errorf("circular assertions are not expected: %s", ref) 78 } 79 if a == nil { 80 retrieved, err := f.retrieve(ref) 81 if err != nil { 82 return err 83 } 84 a = retrieved 85 } 86 f.fetched[u] = fetchRetrieved 87 for _, preref := range a.Prerequisites() { 88 if err := f.Fetch(preref); err != nil { 89 return err 90 } 91 } 92 if err := f.fetchAccountKey(a.SignKeyID()); err != nil { 93 return err 94 } 95 if err := f.save(a); err != nil { 96 return err 97 } 98 f.fetched[u] = fetchSaved 99 return nil 100 } 101 102 // Fetch retrieves the assertion indicated by ref then its prerequisites 103 // recursively, along the way saving prerequisites before dependent assertions. 104 func (f *fetcher) Fetch(ref *Ref) error { 105 return f.chase(ref, nil) 106 } 107 108 // fetchAccountKey behaves like Fetch for the account-key with the given key id. 109 func (f *fetcher) fetchAccountKey(keyID string) error { 110 keyRef := &Ref{ 111 Type: AccountKeyType, 112 PrimaryKey: []string{keyID}, 113 } 114 return f.Fetch(keyRef) 115 } 116 117 // Save retrieves the prerequisites of the assertion recursively, 118 // along the way saving them, and finally saves the assertion. 119 func (f *fetcher) Save(a Assertion) error { 120 return f.chase(a.Ref(), a) 121 }