mirror of
https://github.com/safing/portmaster
synced 2025-04-20 02:49:10 +00:00
* Move portbase into monorepo * Add new simple module mgr * [WIP] Switch to new simple module mgr * Add StateMgr and more worker variants * [WIP] Switch more modules * [WIP] Switch more modules * [WIP] swtich more modules * [WIP] switch all SPN modules * [WIP] switch all service modules * [WIP] Convert all workers to the new module system * [WIP] add new task system to module manager * [WIP] Add second take for scheduling workers * [WIP] Add FIXME for bugs in new scheduler * [WIP] Add minor improvements to scheduler * [WIP] Add new worker scheduler * [WIP] Fix more bug related to new module system * [WIP] Fix start handing of the new module system * [WIP] Improve startup process * [WIP] Fix minor issues * [WIP] Fix missing subsystem in settings * [WIP] Initialize managers in constructor * [WIP] Move module event initialization to constrictors * [WIP] Fix setting for enabling and disabling the SPN module * [WIP] Move API registeration into module construction * [WIP] Update states mgr for all modules * [WIP] Add CmdLine operation support * Add state helper methods to module group and instance * Add notification and module status handling to status package * Fix starting issues * Remove pilot widget and update security lock to new status data * Remove debug logs * Improve http server shutdown * Add workaround for cleanly shutting down firewall+netquery * Improve logging * Add syncing states with notifications for new module system * Improve starting, stopping, shutdown; resolve FIXMEs/TODOs * [WIP] Fix most unit tests * Review new module system and fix minor issues * Push shutdown and restart events again via API * Set sleep mode via interface * Update example/template module * [WIP] Fix spn/cabin unit test * Remove deprecated UI elements * Make log output more similar for the logging transition phase * Switch spn hub and observer cmds to new module system * Fix log sources * Make worker mgr less error prone * Fix tests and minor issues * Fix observation hub * Improve shutdown and restart handling * Split up big connection.go source file * Move varint and dsd packages to structures repo * Improve expansion test * Fix linter warnings * Fix interception module on windows * Fix linter errors --------- Co-authored-by: Vladimir Stoilov <vladimir@safing.io>
156 lines
4 KiB
Go
156 lines
4 KiB
Go
package updater
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"io/fs"
|
|
"os"
|
|
"strings"
|
|
|
|
semver "github.com/hashicorp/go-version"
|
|
|
|
"github.com/safing/jess/filesig"
|
|
"github.com/safing/portmaster/base/log"
|
|
"github.com/safing/portmaster/base/utils"
|
|
)
|
|
|
|
// File represents a file from the update system.
|
|
type File struct {
|
|
resource *Resource
|
|
version *ResourceVersion
|
|
notifier *notifier
|
|
versionedPath string
|
|
storagePath string
|
|
}
|
|
|
|
// Identifier returns the identifier of the file.
|
|
func (file *File) Identifier() string {
|
|
return file.resource.Identifier
|
|
}
|
|
|
|
// Version returns the version of the file.
|
|
func (file *File) Version() string {
|
|
return file.version.VersionNumber
|
|
}
|
|
|
|
// SemVer returns the semantic version of the file.
|
|
func (file *File) SemVer() *semver.Version {
|
|
return file.version.semVer
|
|
}
|
|
|
|
// EqualsVersion normalizes the given version and checks equality with semver.
|
|
func (file *File) EqualsVersion(version string) bool {
|
|
return file.version.EqualsVersion(version)
|
|
}
|
|
|
|
// Path returns the absolute filepath of the file.
|
|
func (file *File) Path() string {
|
|
return file.storagePath
|
|
}
|
|
|
|
// SigningMetadata returns the metadata to be included in signatures.
|
|
func (file *File) SigningMetadata() map[string]string {
|
|
return map[string]string{
|
|
"id": file.Identifier(),
|
|
"version": file.Version(),
|
|
}
|
|
}
|
|
|
|
// Verify verifies the given file.
|
|
func (file *File) Verify() ([]*filesig.FileData, error) {
|
|
// Check if verification is configured.
|
|
if file.resource.VerificationOptions == nil {
|
|
return nil, ErrVerificationNotConfigured
|
|
}
|
|
|
|
// Verify file.
|
|
fileData, err := filesig.VerifyFile(
|
|
file.storagePath,
|
|
file.storagePath+filesig.Extension,
|
|
file.SigningMetadata(),
|
|
file.resource.VerificationOptions.TrustStore,
|
|
)
|
|
if err != nil {
|
|
switch file.resource.VerificationOptions.DiskLoadPolicy {
|
|
case SignaturePolicyRequire:
|
|
return nil, err
|
|
case SignaturePolicyWarn:
|
|
log.Warningf("%s: failed to verify %s: %s", file.resource.registry.Name, file.storagePath, err)
|
|
case SignaturePolicyDisable:
|
|
log.Debugf("%s: failed to verify %s: %s", file.resource.registry.Name, file.storagePath, err)
|
|
}
|
|
}
|
|
|
|
return fileData, nil
|
|
}
|
|
|
|
// Blacklist notifies the update system that this file is somehow broken, and should be ignored from now on, until restarted.
|
|
func (file *File) Blacklist() error {
|
|
return file.resource.Blacklist(file.version.VersionNumber)
|
|
}
|
|
|
|
// markActiveWithLocking marks the file as active, locking the resource in the process.
|
|
func (file *File) markActiveWithLocking() {
|
|
file.resource.Lock()
|
|
defer file.resource.Unlock()
|
|
|
|
// update last used version
|
|
if file.resource.ActiveVersion != file.version {
|
|
log.Debugf("updater: setting active version of resource %s from %s to %s", file.resource.Identifier, file.resource.ActiveVersion, file.version.VersionNumber)
|
|
file.resource.ActiveVersion = file.version
|
|
}
|
|
}
|
|
|
|
// Unpacker describes the function that is passed to
|
|
// File.Unpack. It receives a reader to the compressed/packed
|
|
// file and should return a reader that provides
|
|
// unpacked file contents. If the returned reader implements
|
|
// io.Closer it's close method is invoked when an error
|
|
// or io.EOF is returned from Read().
|
|
type Unpacker func(io.Reader) (io.Reader, error)
|
|
|
|
// Unpack returns the path to the unpacked version of file and
|
|
// unpacks it on demand using unpacker.
|
|
func (file *File) Unpack(suffix string, unpacker Unpacker) (string, error) {
|
|
path := strings.TrimSuffix(file.Path(), suffix)
|
|
|
|
if suffix == "" {
|
|
path += "-unpacked"
|
|
}
|
|
|
|
_, err := os.Stat(path)
|
|
if err == nil {
|
|
return path, nil
|
|
}
|
|
|
|
if !errors.Is(err, fs.ErrNotExist) {
|
|
return "", err
|
|
}
|
|
|
|
f, err := os.Open(file.Path())
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer func() {
|
|
_ = f.Close()
|
|
}()
|
|
|
|
r, err := unpacker(f)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
ioErr := utils.CreateAtomic(path, r, &utils.AtomicFileOptions{
|
|
TempDir: file.resource.registry.TmpDir().Path,
|
|
})
|
|
|
|
if c, ok := r.(io.Closer); ok {
|
|
if err := c.Close(); err != nil && ioErr == nil {
|
|
// if ioErr is already set we ignore the error from
|
|
// closing the unpacker.
|
|
ioErr = err
|
|
}
|
|
}
|
|
|
|
return path, ioErr
|
|
}
|