github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/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  }