update

package
v1.9.1 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: AGPL-3.0 Imports: 21 Imported by: 0

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

View Source
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.

View Source
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.

View Source
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.

View Source
const MaxSize = 128 << 20

MaxSize is the largest download accepted (the installer is ~15 MB).

View Source
const ReleasesPage = "https://github.com/ApolloF/Seaglass/releases/latest"

ReleasesPage is where people download Seaglass by hand.

Variables

View Source
var ErrNoRelease = errors.New("no release published yet")

ErrNoRelease means GitHub has no (non-preview) release yet.

View Source
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.

View Source
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

func CheckPublisher(file, running string) error

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 CleanOld

func CleanOld(exe string)

CleanOld removes the exe an earlier swap moved aside.

func Clear

func Clear(dir, keep string)

Clear removes downloads in dir except keep (a file path, or "").

func DecodeSig

func DecodeSig(b []byte) ([]byte, error)

func EncodeSig

func EncodeSig(sig []byte) []byte

EncodeSig and DecodeSig turn a signature into the .sig file's one line.

func FileSHA256

func FileSHA256(p string) (string, error)

FileSHA256 hashes a file.

func FormatSums

func FormatSums(sums map[string]string) []byte

FormatSums writes name → hash as sha256sum does, sorted by name.

func KindFor

func KindFor(exe string) string

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

func Newer(a, b string) bool

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 ParseKey

func ParseKey(s string) (ed25519.PublicKey, error)

ParseKey reads a base64 public key.

func ParseSums

func ParseSums(b []byte) (map[string]string, error)

ParseSums reads a SHA256SUMS file.

func RunInstaller

func RunInstaller(file, installDir string, relaunch, tray bool) error

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

func SavePending(dir string, p Pending) error

SavePending records the waiting update.

func SignedMessage

func SignedMessage(tag string, sums []byte) []byte

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.

func SwapExe

func SwapExe(newExe, exe string) error

SwapExe puts newExe in the place of the running exe. Windows lets a running exe be renamed, so the old one moves aside to "<exe>.old" (removed by CleanOld on the next start) and the new one takes its name.

func Valid

func Valid(v string) bool

Valid reports whether v is a version Seaglass can compare.

func VerifySums

func VerifySums(keys []ed25519.PublicKey, tag string, sums, sigFile []byte) (map[string]string, error)

VerifySums checks a release's SHA256SUMS against its signature with any of keys, and returns the hashes it lists.

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.

func (Feed) Latest

func (f Feed) Latest(ctx context.Context) (Release, error)

Latest asks GitHub for the newest release.

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

func LoadPending(dir string) (Pending, bool)

LoadPending reads the waiting update in dir, if there is one.

func (Pending) Check

func (p Pending) Check(running string) error

Check makes sure the downloaded file is still the one that was checked, and, when running is signed, that it's signed by the same publisher.

type Release

type Release struct {
	Tag       string // "v1.0.0"
	Notes     string // markdown, shortened
	Page      string // release page on github.com
	Published time.Time
	// contains filtered or unexported fields
}

Release is a published Seaglass release.

func (Release) Asset

func (r Release) Asset(name string) (Asset, bool)

Asset returns the release's file with this name.

Jump to

Keyboard shortcuts

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