store

package
v0.0.0-...-55306fc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 21, 2024 License: GPL-3.0 Imports: 43 Imported by: 143

Documentation

Overview

Package store has support to use the Ubuntu Store for querying and downloading of snaps, and the related services.

Package store has support to use the Ubuntu Store for querying and downloading of snaps, and the related services.

Package store has support to use the Ubuntu Store for querying and downloading of snaps, and the related services.

Package store has support to use the Ubuntu Store for querying and downloading of snaps, and the related services.

Index

Constants

View Source
const (

	// UbuntuCoreWireProtocol is the protocol level we support when
	// communicating with the store. History:
	//  - "1": client supports squashfs snaps
	UbuntuCoreWireProtocol = "1"
)

Variables

View Source
var (

	// macaroonACLAPI points to Developer API endpoint to get an ACL macaroon
	MacaroonACLAPI = developerAPIBase + "dev/api/acl/"

	// UbuntuoneLocation is the Ubuntuone location as defined in the store macaroon
	UbuntuoneLocation = authLocation()
	// UbuntuoneDischargeAPI points to SSO endpoint to discharge a macaroon
	UbuntuoneDischargeAPI = ubuntuoneAPIBase + "/tokens/discharge"
	// UbuntuoneRefreshDischargeAPI points to SSO endpoint to refresh a discharge macaroon
	UbuntuoneRefreshDischargeAPI = ubuntuoneAPIBase + "/tokens/refresh"
)
View Source
var (
	// ErrBadQuery is returned from Find when the query has special characters in strange places.
	ErrBadQuery = errors.New("bad query")

	// ErrInvalidScope is returned from Find when an invalid scope is requested.
	ErrInvalidScope = errors.New("invalid scope")

	// ErrSnapNotFound is returned when a snap can not be found
	ErrSnapNotFound = errors.New("snap not found")

	// ErrUnauthenticated is returned when authentication is needed to complete the query
	ErrUnauthenticated = errors.New("you need to log in first")

	// ErrAuthenticationNeeds2fa is returned if the authentication needs 2factor
	ErrAuthenticationNeeds2fa = errors.New("two factor authentication required")

	// Err2faFailed is returned when 2fa failed (e.g., a bad token was given)
	Err2faFailed = errors.New("two factor authentication failed")

	// ErrInvalidCredentials is returned on login error
	// It can also be returned when refreshing the discharge
	// macaroon if the user has changed their password.
	ErrInvalidCredentials = errors.New("invalid credentials")

	// ErrTOSNotAccepted is returned when the user has not accepted the store's terms of service.
	ErrTOSNotAccepted = errors.New("terms of service not accepted")

	// ErrNoPaymentMethods is returned when the user has no valid payment methods associated with their account.
	ErrNoPaymentMethods = errors.New("no payment methods")

	// ErrPaymentDeclined is returned when the user's payment method was declined by the upstream payment provider.
	ErrPaymentDeclined = errors.New("payment declined")

	// ErrLocalSnap is returned when an operation that only applies to snaps that come from a store was attempted on a local snap.
	ErrLocalSnap = errors.New("cannot perform operation on local snap")

	// ErrNoUpdateAvailable is returned when an update is attempetd for a snap that has no update available.
	ErrNoUpdateAvailable = errors.New("snap has no updates available")
)
View Source
var (
	// ErrNoSerial indicates that a device serial is not set yet.
	ErrNoSerial = errors.New("no device serial yet")
)
View Source
var ErrStoreOffline = errors.New("store is marked offline, use 'snap unset system store.access' to go online")
View Source
var ErrTooManyRequests = errors.New("too many requests")

Functions

func ClientUserAgent

func ClientUserAgent(ctx context.Context) string

ClientUserAgent returns the user agent of the client that talks to snapd

func ResourceToComponentType

func ResourceToComponentType(resType string) (snap.ComponentType, error)

ResourceToComponentType returns a validated component type from a resource type.

func WithClientUserAgent

func WithClientUserAgent(parent context.Context, req *http.Request) context.Context

ClientUserAgentContext carries the client user agent that talks to snapd

Types

type AssertionQuery

type AssertionQuery interface {
	ToResolve() (map[asserts.Grouping][]*asserts.AtRevision, map[asserts.Grouping][]*asserts.AtSequence, error)

	AddError(e error, ref *asserts.Ref) error
	AddSequenceError(e error, atSeq *asserts.AtSequence) error
	AddGroupingError(e error, grouping asserts.Grouping) error
}

type AssertionResult

type AssertionResult struct {
	Grouping   asserts.Grouping
	StreamURLs []string
}

AssertionResult encapsulates the non-error result for one assertion grouping fetch action.

type AuthRefreshNeed

type AuthRefreshNeed struct {
	Device bool
	User   bool
}

AuthRefreshNeed represents which authorization data needs refreshing.

type AuthorizeOptions

type AuthorizeOptions struct {
	// contains filtered or unexported fields
}

type Authorizer

type Authorizer interface {
	// Authorize authorizes the given request.
	// If implementing multiple kind of authorization at the same
	// time all they should be performed separately ignoring
	// errors, as the higher-level code might as well treat Authorize
	// as best-effort and only log any returned error.
	Authorize(r *http.Request, dauthCtx DeviceAndAuthContext, user *auth.UserState, opts *AuthorizeOptions) error

	// CanAuthorizeForUser should return true if the Authorizer
	// can authorize requests on behalf of a user, either
	// by the Authorizer using implicit data or by using auth data
	// carried by UserState, in which case the availability of
	// that explicit data in user should be checked.
	CanAuthorizeForUser(user *auth.UserState) bool
}

An Authorizer can authorize a request using credentials directly or indirectly available.

type CacheManager

type CacheManager struct {
	// contains filtered or unexported fields
}

cacheManager implements a downloadCache via content based hard linking

func NewCacheManager

func NewCacheManager(cacheDir string, maxItems int) *CacheManager

NewCacheManager returns a new CacheManager with the given cacheDir and the given maximum amount of items. The idea behind it is the following algorithm:

  1. When starting a download, check if it exists in $cacheDir
  2. If found, update its mtime, hardlink into target location, and return success
  3. If not found, download the snap
  4. On success, hardlink into $cacheDir/<digest>
  5. If cache dir has more than maxItems entries, remove oldest mtimes until it has maxItems

The caching part is done here, the downloading happens in the store.go code.

func (*CacheManager) Get

func (cm *CacheManager) Get(cacheKey, targetPath string) bool

Get retrieves the given cacheKey content and puts it into targetPath. Returns true if a cached file was moved to targetPath or if one was already there.

func (*CacheManager) GetPath

func (cm *CacheManager) GetPath(cacheKey string) string

GetPath returns the full path of the given content in the cache or empty string

func (*CacheManager) Put

func (cm *CacheManager) Put(cacheKey, sourcePath string) error

Put adds a new file to the cache with the given cacheKey

type CategoryDetails

type CategoryDetails struct {
	Name string `json:"name"`
}

type Config

type Config struct {
	// Store API base URLs. The assertions url is only separate because it can
	// be overridden by its own env var.
	StoreBaseURL      *url.URL
	AssertionsBaseURL *url.URL

	// Authorizer used to authorize requests, can be nil and a default
	// will be used.
	Authorizer Authorizer

	// StoreID is the store id used if we can't get one through the DeviceAndAuthContext.
	StoreID string

	Architecture string
	Series       string

	DetailFields []string
	InfoFields   []string
	// search v2 fields
	FindFields  []string
	DeltaFormat string

	// CacheDownloads is the number of downloads that should be cached
	CacheDownloads int

	// Proxy returns the HTTP proxy to use when talking to the store
	Proxy func(*http.Request) (*url.URL, error)

	// AssertionMaxFormats if set provides a way to override
	// the assertion max formats sent to the store as supported.
	AssertionMaxFormats map[string]int
}

Config represents the configuration to access the snap store

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a copy of the default configuration ready to be adapted.

type CurrentSnap

type CurrentSnap struct {
	InstanceName     string
	SnapID           string
	Revision         snap.Revision
	TrackingChannel  string
	RefreshedDate    time.Time
	IgnoreValidation bool
	Block            []snap.Revision
	Epoch            snap.Epoch
	CohortKey        string
	// ValidationSets is an optional array of validation set primary keys.
	ValidationSets []snapasserts.ValidationSetKey
	// HeldBy is an optional array of snaps with holds on the current snap's
	// refreshes. The "system" snap represents a hold placed by the user.
	HeldBy []string
	// Resources is a map of resource names to the resource revision that is
	// currently installed for the snap.
	Resources map[string]snap.Revision
}

type DeviceAndAuthContext

type DeviceAndAuthContext interface {
	Device() (*auth.DeviceState, error)

	UpdateDeviceAuth(device *auth.DeviceState, sessionMacaroon string) (actual *auth.DeviceState, err error)

	UpdateUserAuth(user *auth.UserState, discharges []string) (actual *auth.UserState, err error)

	StoreID(fallback string) (string, error)

	DeviceSessionRequestParams(nonce string) (*DeviceSessionRequestParams, error)
	ProxyStoreParams(defaultURL *url.URL) (proxyStoreID string, proxySroreURL *url.URL, err error)

	CloudInfo() (*auth.CloudInfo, error)

	StoreOffline() (bool, error)
}

A DeviceAndAuthContext mediates access to device and auth information for the store.

type DeviceSessionRequestParams

type DeviceSessionRequestParams struct {
	Request *asserts.DeviceSessionRequest
	Serial  *asserts.Serial
	Model   *asserts.Model
}

DeviceSessionRequestParams gathers the assertions and information to be sent to request a device session.

func (*DeviceSessionRequestParams) EncodedModel

func (p *DeviceSessionRequestParams) EncodedModel() string

func (*DeviceSessionRequestParams) EncodedRequest

func (p *DeviceSessionRequestParams) EncodedRequest() string

func (*DeviceSessionRequestParams) EncodedSerial

func (p *DeviceSessionRequestParams) EncodedSerial() string

type DownloadError

type DownloadError struct {
	Code int
	URL  *url.URL
}

DownloadError represents a download error

func (*DownloadError) Error

func (e *DownloadError) Error() string

type DownloadOptions

type DownloadOptions struct {
	RateLimit           int64
	Scheduled           bool
	LeavePartialOnError bool
}

type HashError

type HashError struct {
	// contains filtered or unexported fields
}

func (HashError) Error

func (e HashError) Error() string

type InvalidAuthDataError

type InvalidAuthDataError map[string]stringList

InvalidAuthDataError signals that the authentication data didn't pass validation.

func (InvalidAuthDataError) Error

func (e InvalidAuthDataError) Error() string

type PasswordPolicyError

type PasswordPolicyError map[string]stringList

PasswordPolicyError is returned in a few corner cases, most notably when the password has been force-reset.

func (PasswordPolicyError) Error

func (e PasswordPolicyError) Error() string

type RefreshOptions

type RefreshOptions struct {
	// RefreshManaged indicates to the store that the refresh is
	// managed via snapd-control.
	RefreshManaged bool
	Scheduled      bool

	PrivacyKey string

	// IncludeResources indicates to the store that resources should be included
	// in the response.
	IncludeResources bool
}

TODO: rename this type to something more general, since it is used for more than just refreshes

type RefreshingAuthorizer

type RefreshingAuthorizer interface {
	Authorizer

	// Refresh transient authorization data.
	RefreshAuth(need AuthRefreshNeed, dauthCtx DeviceAndAuthContext, user *auth.UserState, client *http.Client) error
}

type RevisionNotAvailableError

type RevisionNotAvailableError struct {
	Action   string
	Channel  string
	Releases []channel.Channel
}

RevisionNotAvailableError is returned when an install is attempted for a snap but the/a revision is not available (given install constraints).

func (*RevisionNotAvailableError) Error

func (e *RevisionNotAvailableError) Error() string
type Search struct {
	// Query is a term to search by or a prefix (if Prefix is true)
	Query  string
	Prefix bool

	CommonID string

	// category is "section" in search v1
	Category string
	Private  bool
	Scope    string
}

A Search is what you do in order to Find something

type SnapAction

type SnapAction struct {
	Action       string
	InstanceName string
	SnapID       string
	Channel      string
	Revision     snap.Revision
	CohortKey    string
	Flags        SnapActionFlags
	Epoch        snap.Epoch
	// ResourceInstall is a flag that indicates that this action is being used
	// to fetch the list of resources that are available for a snap. This flag
	// impacts how we decide to report an error if the snap has no updates
	// available.
	ResourceInstall bool
	// ValidationSets is an optional array of validation set primary keys
	// (relevant for install and refresh actions).
	ValidationSets []snapasserts.ValidationSetKey
}

type SnapActionError

type SnapActionError struct {
	// NoResults is set if there were no results in the response
	NoResults bool
	// Refresh errors by snap name.
	Refresh map[string]error
	// Install errors by snap name.
	Install map[string]error
	// Download errors by snap name.
	Download map[string]error
	// Other errors.
	Other []error
}

SnapActionError conveys errors that were reported on otherwise overall successful snap action (install/refresh) request.

func (SnapActionError) Error

func (e SnapActionError) Error() string

func (SnapActionError) SingleOpError

func (e SnapActionError) SingleOpError() (op, name string, err error)

SingleOpError returns the single operation, snap name, and error if e represents a single error of a single operation on a single snap (i.e. if e.Other is empty, and e.Refresh, e.Install and e.Download have a single error in total). In any other case, the error returned will be nil.

type SnapActionFlags

type SnapActionFlags int
const (
	SnapActionIgnoreValidation SnapActionFlags = 1 << iota
	SnapActionEnforceValidation
)

type SnapActionResult

type SnapActionResult struct {
	*snap.Info
	Resources       []SnapResourceResult
	RedirectChannel string
}

SnapActionResult encapsulates the non-error result of a single action of the SnapAction call.

func (*SnapActionResult) ResourceResult

func (sar *SnapActionResult) ResourceResult(resName string) *SnapResourceResult

type SnapAdder

type SnapAdder interface {
	AddSnap(snapName, version, summary string, commands []string) error
}

type SnapResourceResult

type SnapResourceResult struct {
	DownloadInfo snap.DownloadInfo
	Type         string
	Name         string
	Revision     int
	Version      string
	CreatedAt    string
}

type SnapSpec

type SnapSpec struct {
	Name string
}

A SnapSpec describes a single snap wanted from SnapInfo

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store represents the ubuntu snap store

func New

func New(cfg *Config, dauthCtx DeviceAndAuthContext) *Store

New creates a new Store with the given access configuration and for given the store id.

func (*Store) Assertion

func (s *Store) Assertion(assertType *asserts.AssertionType, primaryKey []string, user *auth.UserState) (asserts.Assertion, error)

Assertion retrieves the assertion for the given type and primary key.

func (*Store) Buy

func (s *Store) Buy(options *client.BuyOptions, user *auth.UserState) (*client.BuyResult, error)

Buy sends a buy request for the specified snap. Returns the state of the order: Complete, Cancelled.

func (*Store) CacheDownloads

func (s *Store) CacheDownloads() int

func (*Store) Categories

func (s *Store) Categories(ctx context.Context, user *auth.UserState) ([]CategoryDetails, error)

Categories retrieves the list of available store categories.

func (*Store) ConnectivityCheck

func (s *Store) ConnectivityCheck() (status map[string]bool, err error)

func (*Store) CreateCohorts

func (s *Store) CreateCohorts(ctx context.Context, snaps []string) (map[string]string, error)

func (*Store) Download

func (s *Store) Download(ctx context.Context, name string, targetPath string, downloadInfo *snap.DownloadInfo, pbar progress.Meter, user *auth.UserState, dlOpts *DownloadOptions) error

Download downloads the snap addressed by download info and returns its filename. The file is saved in temporary storage, and should be removed after use to prevent the disk from running out of space.

func (*Store) DownloadAssertions

func (s *Store) DownloadAssertions(streamURLs []string, b *asserts.Batch, user *auth.UserState) error

DownloadAssertions download the assertion streams at the given URLs and adds their assertions to the given asserts.Batch.

func (*Store) DownloadStream

func (s *Store) DownloadStream(ctx context.Context, name string, downloadInfo *snap.DownloadInfo, resume int64, user *auth.UserState) (io.ReadCloser, int, error)

DownloadStream will copy the snap from the request to the io.Reader

func (*Store) EnsureDeviceSession

func (s *Store) EnsureDeviceSession() error

EnsureDeviceSession makes sure the store has a device session available. Expects the store to have an AuthContext.

func (*Store) Find

func (s *Store) Find(ctx context.Context, search *Search, user *auth.UserState) ([]*snap.Info, error)

Find finds (installable) snaps from the store, matching the given Search.

func (*Store) LoginUser

func (s *Store) LoginUser(username, password, otp string) (string, string, error)

LoginUser logs user in the store and returns the authentication macaroons.

func (*Store) ReadyToBuy

func (s *Store) ReadyToBuy(user *auth.UserState) error

ReadyToBuy returns nil if the user's account has accepted T&Cs and has a payment method registered, and an error otherwise

func (*Store) Sections

func (s *Store) Sections(ctx context.Context, user *auth.UserState) ([]string, error)

Sections retrieves the list of available store sections.

func (*Store) SeqFormingAssertion

func (s *Store) SeqFormingAssertion(assertType *asserts.AssertionType, sequenceKey []string, sequence int, user *auth.UserState) (asserts.Assertion, error)

SeqFormingAssertion retrieves the sequence-forming assertion for the given type (currently validation-set only). For sequence <= 0 we query for the latest sequence, otherwise the latest revision of the given sequence is requested.

func (*Store) SetAssertionMaxFormats

func (s *Store) SetAssertionMaxFormats(maxFormats map[string]int)

SetAssertionMaxFormats allows to change the assertion max formats to send for a store already in use.

func (*Store) SetCacheDownloads

func (s *Store) SetCacheDownloads(fileCount int)

func (*Store) SnapAction

func (s *Store) SnapAction(ctx context.Context, currentSnaps []*CurrentSnap, actions []*SnapAction, assertQuery AssertionQuery, user *auth.UserState, opts *RefreshOptions) ([]SnapActionResult, []AssertionResult, error)

SnapAction queries the store for snap information for the given install/refresh actions, given the context information about current installed snaps in currentSnaps. If the request was overall successful (200) but there were reported errors it will return both the snap infos and an SnapActionError. Orthogonally and at the same time it can be used to fetch or update assertions by passing an AssertionQuery whose ToResolve specifies the assertions and revisions to consider. Assertion related errors are reported via the AssertionQuery Add*Error methods.

func (*Store) SnapExists

func (s *Store) SnapExists(ctx context.Context, snapSpec SnapSpec, user *auth.UserState) (naming.SnapRef, *channel.Channel, error)

SnapInfo checks whether the store-hosted snap matching the given spec exists and returns a reference with it name and snap-id and default channel, or an error.

func (*Store) SnapInfo

func (s *Store) SnapInfo(ctx context.Context, snapSpec SnapSpec, user *auth.UserState) (*snap.Info, error)

SnapInfo returns the snap.Info for the store-hosted snap matching the given spec, or an error.

func (*Store) SuggestedCurrency

func (s *Store) SuggestedCurrency() string

SuggestedCurrency retrieves the cached value for the store's suggested currency

func (*Store) UserInfo

func (s *Store) UserInfo(email string) (userinfo *User, err error)

func (*Store) WriteCatalogs

func (s *Store) WriteCatalogs(ctx context.Context, names io.Writer, adder SnapAdder) error

WriteCatalogs queries the "commands" endpoint and writes the command names into the given io.Writer.

type TransferSpeedMonitoringWriter

type TransferSpeedMonitoringWriter struct {
	// contains filtered or unexported fields
}

implements io.Writer interface XXX: move to osutil?

func NewTransferSpeedMonitoringWriterAndContext

func NewTransferSpeedMonitoringWriterAndContext(origCtx context.Context, measureTimeWindow time.Duration, minDownloadSpeedBps float64) (*TransferSpeedMonitoringWriter, context.Context)

NewTransferSpeedMonitoringWriterAndContext returns an io.Writer that measures write speed in measureTimeWindow windows and cancels the operation if minDownloadSpeedBps is not achieved. Monitor() must be called to start actual measurement.

func (*TransferSpeedMonitoringWriter) Err

Err returns the transferSpeedError if encountered when measurement was run.

func (*TransferSpeedMonitoringWriter) Monitor

func (w *TransferSpeedMonitoringWriter) Monitor() (quit chan bool)

Monitor starts a new measurement for write operations and returns a quit channel that should be closed by the caller to finish the measurement.

func (*TransferSpeedMonitoringWriter) Write

func (w *TransferSpeedMonitoringWriter) Write(p []byte) (n int, err error)

type UnexpectedHTTPStatusError

type UnexpectedHTTPStatusError struct {
	OpSummary  string
	StatusCode int
	Method     string
	URL        *url.URL
	OopsID     string
}

UnexpectedHTTPStatusError represents an error where the store returned an unexpected HTTP status code, i.e. a status code that doesn't represent success nor an expected error condition with known handling (e.g. a 404 when instead presence is always expected).

func (*UnexpectedHTTPStatusError) Error

func (e *UnexpectedHTTPStatusError) Error() string

type User

type User struct {
	Username         string
	SSHKeys          []string
	OpenIDIdentifier string
}

type UserAuthUpdater

type UserAuthUpdater interface {
	UpdateUserAuth(user *auth.UserState, discharges []string) (actual *auth.UserState, err error)
}

type UserAuthorizer

type UserAuthorizer struct{}

UserAuthorizer authorizes requests using user credentials managed via the DeviceAndAuthContext.

func (UserAuthorizer) Authorize

func (UserAuthorizer) CanAuthorizeForUser

func (a UserAuthorizer) CanAuthorizeForUser(user *auth.UserState) bool

func (UserAuthorizer) RefreshAuth

func (a UserAuthorizer) RefreshAuth(need AuthRefreshNeed, dauthCtx DeviceAndAuthContext, user *auth.UserState, client *http.Client) error

func (UserAuthorizer) RefreshUser

func (a UserAuthorizer) RefreshUser(user *auth.UserState, upd UserAuthUpdater, client *http.Client) error

RefreshUser will refresh user discharge macaroon and update state via the UserAuthUpdater.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL