gitee.com/mysnapcore/mysnapd@v0.1.0/asserts/fetcher.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2022 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 //nolint:deadcode 30 fetchNotSeen fetchProgress = iota 31 fetchRetrieved 32 fetchSaved 33 ) 34 35 // A Fetcher helps fetching assertions and their prerequisites. 36 type Fetcher interface { 37 // Fetch retrieves the assertion indicated by ref then its prerequisites 38 // recursively, along the way saving prerequisites before dependent assertions. 39 Fetch(*Ref) error 40 // Save retrieves the prerequisites of the assertion recursively, 41 // along the way saving them, and finally saves the assertion. 42 Save(Assertion) error 43 } 44 45 type fetcher struct { 46 db RODatabase 47 retrieve func(*Ref) (Assertion, error) 48 save func(Assertion) error 49 50 fetched map[string]fetchProgress 51 } 52 53 // 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. 54 func NewFetcher(trustedDB RODatabase, retrieve func(*Ref) (Assertion, error), save func(Assertion) error) Fetcher { 55 return &fetcher{ 56 db: trustedDB, 57 retrieve: retrieve, 58 save: save, 59 fetched: make(map[string]fetchProgress), 60 } 61 } 62 63 func (f *fetcher) chase(ref *Ref, a Assertion) error { 64 // check if ref points to predefined assertion, in which case 65 // there is nothing to do 66 _, err := ref.Resolve(f.db.FindPredefined) 67 if err == nil { 68 return nil 69 } 70 if !IsNotFound(err) { 71 return err 72 } 73 u := ref.Unique() 74 switch f.fetched[u] { 75 case fetchSaved: 76 return nil // nothing to do 77 case fetchRetrieved: 78 return fmt.Errorf("circular assertions are not expected: %s", ref) 79 } 80 if a == nil { 81 retrieved, err := f.retrieve(ref) 82 if err != nil { 83 return err 84 } 85 a = retrieved 86 } 87 f.fetched[u] = fetchRetrieved 88 for _, preref := range a.Prerequisites() { 89 if err := f.Fetch(preref); err != nil { 90 return err 91 } 92 } 93 if err := f.fetchAccountKey(a.SignKeyID()); err != nil { 94 return err 95 } 96 if err := f.save(a); err != nil { 97 return err 98 } 99 f.fetched[u] = fetchSaved 100 return nil 101 } 102 103 // Fetch retrieves the assertion indicated by ref then its prerequisites 104 // recursively, along the way saving prerequisites before dependent assertions. 105 func (f *fetcher) Fetch(ref *Ref) error { 106 return f.chase(ref, nil) 107 } 108 109 // fetchAccountKey behaves like Fetch for the account-key with the given key id. 110 func (f *fetcher) fetchAccountKey(keyID string) error { 111 keyRef := &Ref{ 112 Type: AccountKeyType, 113 PrimaryKey: []string{keyID}, 114 } 115 return f.Fetch(keyRef) 116 } 117 118 // Save retrieves the prerequisites of the assertion recursively, 119 // along the way saving them, and finally saves the assertion. 120 func (f *fetcher) Save(a Assertion) error { 121 return f.chase(a.Ref(), a) 122 }