Documentation
¶
Overview ¶
Package update keeps Seaglass up to date from its GitHub releases.
It asks GitHub for the newest release (prereleases don't count), downloads the installer (or, for a copy that wasn't installed, the bare exe) together with its published SHA-256, and checks the hash, and the Authenticode publisher when the running exe is signed, before the file is ever run. Downloads come only from the repository's own release assets.
Index ¶
- Constants
- Variables
- func CheckPublisher(file, running string) error
- func CleanOld(exe string)
- func Clear(dir, keep string)
- func DecodeSig(b []byte) ([]byte, error)
- func EncodeSig(sig []byte) []byte
- func FileSHA256(p string) (string, error)
- func FormatSums(sums map[string]string) []byte
- func KindFor(exe string) string
- func Newer(a, b string) bool
- func ParseKey(s string) (ed25519.PublicKey, error)
- func ParseSums(b []byte) (map[string]string, error)
- func RunInstaller(file, installDir string, relaunch, tray bool) error
- func SavePending(dir string, p Pending) error
- func SignedMessage(tag string, sums []byte) []byte
- func SwapExe(newExe, exe string) error
- func Valid(v string) bool
- func VerifySums(keys []ed25519.PublicKey, tag string, sums, sigFile []byte) (map[string]string, error)
- type Asset
- type Feed
- type Pending
- type Release
Constants ¶
const ( KindInstaller = "installer" // Seaglass was installed: run the new installer silently KindExe = "exe" // a copy that wasn't installed: swap the exe )
How an update is put in place.
const ( SumsAsset = "SHA256SUMS" SigAsset = "SHA256SUMS.sig" )
Release signatures. Every release carries SHA256SUMS (the SHA-256 of each file) and SHA256SUMS.sig, an ed25519 signature made with a key that is kept offline, away from GitHub (tools/release). The updater only installs a download whose hash is in a SHA256SUMS signed by one of ReleaseKeys, so someone who takes over the GitHub account can't ship an update.
const ( InstallerAsset = "Seaglass-setup.exe" ExeAsset = "Seaglass.exe" )
Asset names every release carries. They stay the same across versions, so github.com/…/releases/latest/download/<name> always points at the newest.
const MaxSize = 128 << 20
MaxSize is the largest download accepted (the installer is ~15 MB).
const ReleasesPage = "https://github.com/ApolloF/Seaglass/releases/latest"
ReleasesPage is where people download Seaglass by hand.
Variables ¶
var ErrNoRelease = errors.New("no release published yet")
ErrNoRelease means GitHub has no (non-preview) release yet.
var GitHub = Feed{ LatestURL: "https://api.github.com/repos/ApolloF/Seaglass/releases/latest", AssetPrefix: "https://github.com/ApolloF/Seaglass/releases/download/", Hosts: []string{"github.com", "release-assets.githubusercontent.com", "objects.githubusercontent.com"}, Keys: ReleaseKeys, }
GitHub is Seaglass's own release feed.
var ReleaseKeys = mustKeys(
"B59dCTxm8VjribRDfgl4nfwp1O4jQZjpfY6SVR+AprQ=",
)
ReleaseKeys verify release signatures (see signature.go). The private key never touches GitHub: it's on the maintainer's PC, with an offline backup (tools/release). To rotate, add the new key here in a release signed with the old one, and remove the old one a release later.
Functions ¶
func CheckPublisher ¶
CheckPublisher refuses a file that isn't signed by the running exe's publisher. While Seaglass itself is unsigned, the SHA-256 published with the release is the check.
func Clear ¶
func Clear(dir, keep string)
Clear removes downloads in dir except keep (a file path, or "").
func FormatSums ¶
FormatSums writes name → hash as sha256sum does, sorted by name.
func KindFor ¶
KindFor says how an update reaches the exe at path: through the installer when it was installed (its uninstaller sits next to it), by swapping the exe when its folder is writable, or not at all ("": the user downloads it by hand).
func Newer ¶
Newer reports whether version tag a is newer than b ("v1.2.3", "1.2"). Anything that isn't a version (like "dev") is never newer nor older.
func RunInstaller ¶
RunInstaller starts the installer silently, into the folder Seaglass is installed in. With relaunch it starts Seaglass again when it's done (in the tray with tray). The caller quits right after; the installer waits for it to exit.
func SavePending ¶
SavePending records the waiting update.
func SignedMessage ¶
SignedMessage is what a release signature covers: the tag as well as the hashes, so an old release can't be passed off under a newer tag.
Types ¶
type Asset ¶
type Asset struct {
Name string
URL string
Size int64
Digest string // SHA-256 GitHub computed on upload ("sha256:<hex>"), when it did
}
Asset is one downloadable file of a release.
type Feed ¶
type Feed struct {
LatestURL string // GitHub's "latest release" API endpoint
AssetPrefix string // every download URL must start with this
Hosts []string // hosts a download may be redirected to
Client *http.Client
// Keys are the release keys; with any, only files listed in a signed
// SHA256SUMS are accepted.
Keys []ed25519.PublicKey
}
Feed is where releases come from.
func (Feed) Download ¶
func (f Feed) Download(ctx context.Context, rel Release, name, dir string, progress func(done, total int64)) (string, string, error)
Download fetches the release asset called name into dir and checks it: against the release's signed SHA256SUMS when the feed has release keys, else against its published "<name>.sha256", or else the SHA-256 GitHub computed when the file was uploaded. It returns the file's path and SHA-256. progress (optional) hears how far it got.
type Pending ¶
type Pending struct {
Tag string `json:"tag"`
File string `json:"file"`
SHA256 string `json:"sha256"`
Kind string `json:"kind"`
Attempts int `json:"attempts"` // installs started; one that didn't take isn't retried on its own
}
Pending is a downloaded, checked update waiting to be installed. It is kept in pending.json next to the download.
func LoadPending ¶
LoadPending reads the waiting update in dir, if there is one.