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  }