mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
199 lines
5.5 KiB
Go
199 lines
5.5 KiB
Go
// -*- Mode: Go; indent-tabs-mode: t -*-
|
|
|
|
/*
|
|
* Copyright (C) 2015-2022 Canonical Ltd
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
package daemon
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gorilla/mux"
|
|
|
|
"github.com/snapcore/snapd/overlord/assertstate"
|
|
"github.com/snapcore/snapd/overlord/auth"
|
|
"github.com/snapcore/snapd/overlord/configstate"
|
|
"github.com/snapcore/snapd/overlord/registrystate"
|
|
"github.com/snapcore/snapd/overlord/snapstate"
|
|
"github.com/snapcore/snapd/overlord/state"
|
|
"github.com/snapcore/snapd/strutil"
|
|
)
|
|
|
|
var api = []*Command{
|
|
rootCmd,
|
|
sysInfoCmd,
|
|
loginCmd,
|
|
logoutCmd,
|
|
appIconCmd,
|
|
findCmd,
|
|
snapsCmd,
|
|
snapCmd,
|
|
snapFileCmd,
|
|
snapDownloadCmd,
|
|
snapConfCmd,
|
|
interfacesCmd,
|
|
assertsCmd,
|
|
assertsFindManyCmd,
|
|
stateChangeCmd,
|
|
stateChangesCmd,
|
|
createUserCmd,
|
|
buyCmd,
|
|
readyToBuyCmd,
|
|
snapctlCmd,
|
|
usersCmd,
|
|
sectionsCmd,
|
|
categoriesCmd,
|
|
aliasesCmd,
|
|
appsCmd,
|
|
logsCmd,
|
|
warningsCmd,
|
|
debugPprofCmd,
|
|
debugCmd,
|
|
snapshotCmd,
|
|
snapshotExportCmd,
|
|
connectionsCmd,
|
|
modelCmd,
|
|
cohortsCmd,
|
|
serialModelCmd,
|
|
systemsCmd,
|
|
systemsActionCmd,
|
|
themesCmd,
|
|
accessoriesChangeCmd,
|
|
validationSetsListCmd,
|
|
validationSetsCmd,
|
|
routineConsoleConfStartCmd,
|
|
systemRecoveryKeysCmd,
|
|
quotaGroupsCmd,
|
|
quotaGroupInfoCmd,
|
|
registryCmd,
|
|
noticesCmd,
|
|
noticeCmd,
|
|
}
|
|
|
|
const (
|
|
polkitActionLogin = "io.snapcraft.snapd.login"
|
|
polkitActionManage = "io.snapcraft.snapd.manage"
|
|
polkitActionManageInterfaces = "io.snapcraft.snapd.manage-interfaces"
|
|
polkitActionManageConfiguration = "io.snapcraft.snapd.manage-configuration"
|
|
)
|
|
|
|
// userFromRequest extracts user information from request and return the respective user in state, if valid
|
|
// It requires the state to be locked
|
|
func userFromRequest(st *state.State, req *http.Request) (*auth.UserState, error) {
|
|
// extract macaroons data from request
|
|
header := req.Header.Get("Authorization")
|
|
if header == "" {
|
|
return nil, auth.ErrInvalidAuth
|
|
}
|
|
|
|
authorizationData := strings.SplitN(header, " ", 2)
|
|
if len(authorizationData) != 2 || authorizationData[0] != "Macaroon" {
|
|
return nil, fmt.Errorf("authorization header misses Macaroon prefix")
|
|
}
|
|
|
|
var macaroon string
|
|
var discharges []string
|
|
for _, field := range strutil.CommaSeparatedList(authorizationData[1]) {
|
|
if strings.HasPrefix(field, `root="`) {
|
|
macaroon = strings.TrimSuffix(field[6:], `"`)
|
|
}
|
|
if strings.HasPrefix(field, `discharge="`) {
|
|
discharges = append(discharges, strings.TrimSuffix(field[11:], `"`))
|
|
}
|
|
}
|
|
|
|
if macaroon == "" {
|
|
return nil, fmt.Errorf("invalid authorization header")
|
|
}
|
|
|
|
user, err := auth.CheckMacaroon(st, macaroon, discharges)
|
|
return user, err
|
|
}
|
|
|
|
var muxVars = mux.Vars
|
|
|
|
func storeFrom(d *Daemon) snapstate.StoreService {
|
|
st := d.overlord.State()
|
|
st.Lock()
|
|
defer st.Unlock()
|
|
|
|
return snapstate.Store(st, nil)
|
|
}
|
|
|
|
var (
|
|
snapstateInstall = snapstate.Install
|
|
snapstateInstallPath = snapstate.InstallPath
|
|
snapstateInstallPathMany = snapstate.InstallPathMany
|
|
snapstateInstallComponentPath = snapstate.InstallComponentPath
|
|
snapstateRefreshCandidates = snapstate.RefreshCandidates
|
|
snapstateTryPath = snapstate.TryPath
|
|
snapstateUpdate = snapstate.Update
|
|
snapstateUpdateMany = snapstate.UpdateMany
|
|
snapstateInstallMany = snapstate.InstallMany
|
|
snapstateRemoveMany = snapstate.RemoveMany
|
|
snapstateResolveValSetsEnforcementError = snapstate.ResolveValidationSetsEnforcementError
|
|
snapstateRevert = snapstate.Revert
|
|
snapstateRevertToRevision = snapstate.RevertToRevision
|
|
snapstateSwitch = snapstate.Switch
|
|
snapstateProceedWithRefresh = snapstate.ProceedWithRefresh
|
|
snapstateHoldRefreshesBySystem = snapstate.HoldRefreshesBySystem
|
|
snapstateLongestGatingHold = snapstate.LongestGatingHold
|
|
snapstateSystemHold = snapstate.SystemHold
|
|
snapstateRemoveComponents = snapstate.RemoveComponents
|
|
|
|
configstateConfigureInstalled = configstate.ConfigureInstalled
|
|
|
|
assertstateRefreshSnapAssertions = assertstate.RefreshSnapAssertions
|
|
assertstateRestoreValidationSetsTracking = assertstate.RestoreValidationSetsTracking
|
|
|
|
registrystateGetViaView = registrystate.GetViaView
|
|
registrystateSetViaView = registrystate.SetViaView
|
|
)
|
|
|
|
func ensureStateSoonImpl(st *state.State) {
|
|
st.EnsureBefore(0)
|
|
}
|
|
|
|
var ensureStateSoon = ensureStateSoonImpl
|
|
|
|
func newChange(st *state.State, kind, summary string, tsets []*state.TaskSet, snapNames []string) *state.Change {
|
|
chg := st.NewChange(kind, summary)
|
|
for _, ts := range tsets {
|
|
chg.AddAll(ts)
|
|
}
|
|
if snapNames != nil {
|
|
chg.Set("snap-names", snapNames)
|
|
}
|
|
return chg
|
|
}
|
|
|
|
func isTrue(form *Form, key string) bool {
|
|
values := form.Values[key]
|
|
if len(values) == 0 {
|
|
return false
|
|
}
|
|
b, err := strconv.ParseBool(values[0])
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
return b
|
|
}
|