safing-portmaster/updates/api.go

106 lines
2.7 KiB
Go

package updates
import (
"io"
"net/http"
"os"
"path/filepath"
"github.com/safing/portbase/api"
"github.com/safing/portbase/log"
"github.com/safing/portbase/utils"
)
const (
apiPathCheckForUpdates = "updates/check"
)
func registerAPIEndpoints() error {
if err := api.RegisterEndpoint(api.Endpoint{
Name: "Check for Updates",
Description: "Checks if new versions are available. If automatic updates are enabled, they are also downloaded and applied.",
Parameters: []api.Parameter{{
Method: http.MethodPost,
Field: "download",
Value: "",
Description: "Force downloading and applying of all updates, regardless of auto-update settings.",
}},
Path: apiPathCheckForUpdates,
Write: api.PermitUser,
BelongsTo: module,
ActionFunc: func(r *api.Request) (msg string, err error) {
// Check if we should also download regardless of settings.
downloadAll := r.URL.Query().Has("download")
// Trigger update task.
err = TriggerUpdate(true, downloadAll)
if err != nil {
return "", err
}
// Report how we triggered.
if downloadAll {
return "downloading all updates...", nil
}
return "checking for updates...", nil
},
}); err != nil {
return err
}
if err := api.RegisterEndpoint(api.Endpoint{
Name: "Get Resource",
Description: "Returns the requested resource from the udpate system",
Path: `updates/get/{identifier:[A-Za-z0-9/\.\-_]{1,255}}`,
Read: api.PermitUser,
ReadMethod: http.MethodGet,
BelongsTo: module,
HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
// Get identifier from URL.
var identifier string
if ar := api.GetAPIRequest(r); ar != nil {
identifier = ar.URLVars["identifier"]
}
if identifier == "" {
http.Error(w, "no resource speicified", http.StatusBadRequest)
return
}
// Get resource.
resource, err := registry.GetFile(identifier)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
// Open file for reading.
file, err := os.Open(resource.Path())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer file.Close() //nolint:errcheck
// Add version to header.
w.Header().Set("Resource-Version", resource.Version())
// Set Content-Type.
contentType, _ := utils.MimeTypeByExtension(filepath.Ext(resource.Path()))
w.Header().Set("Content-Type", contentType)
// Write file.
w.WriteHeader(http.StatusOK)
if r.Method != http.MethodHead {
_, err = io.Copy(w, file)
if err != nil {
log.Errorf("updates: failed to serve resource file: %s", err)
return
}
}
},
}); err != nil {
return err
}
return nil
}