github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/daemon/api.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2015-2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package daemon 21 22 import ( 23 "fmt" 24 "mime/multipart" 25 "net/http" 26 "strconv" 27 "strings" 28 29 "github.com/gorilla/mux" 30 31 "github.com/snapcore/snapd/overlord/assertstate" 32 "github.com/snapcore/snapd/overlord/auth" 33 "github.com/snapcore/snapd/overlord/snapstate" 34 "github.com/snapcore/snapd/overlord/state" 35 "github.com/snapcore/snapd/strutil" 36 ) 37 38 var api = []*Command{ 39 rootCmd, 40 sysInfoCmd, 41 loginCmd, 42 logoutCmd, 43 appIconCmd, 44 findCmd, 45 snapsCmd, 46 snapCmd, 47 snapFileCmd, 48 snapDownloadCmd, 49 snapConfCmd, 50 interfacesCmd, 51 assertsCmd, 52 assertsFindManyCmd, 53 stateChangeCmd, 54 stateChangesCmd, 55 createUserCmd, 56 buyCmd, 57 readyToBuyCmd, 58 snapctlCmd, 59 usersCmd, 60 sectionsCmd, 61 aliasesCmd, 62 appsCmd, 63 logsCmd, 64 warningsCmd, 65 debugPprofCmd, 66 debugCmd, 67 snapshotCmd, 68 snapshotExportCmd, 69 connectionsCmd, 70 modelCmd, 71 cohortsCmd, 72 serialModelCmd, 73 systemsCmd, 74 systemsActionCmd, 75 themesCmd, 76 validationSetsListCmd, 77 validationSetsCmd, 78 routineConsoleConfStartCmd, 79 systemRecoveryKeysCmd, 80 quotaGroupsCmd, 81 quotaGroupInfoCmd, 82 } 83 84 const ( 85 polkitActionLogin = "io.snapcraft.snapd.login" 86 polkitActionManage = "io.snapcraft.snapd.manage" 87 polkitActionManageInterfaces = "io.snapcraft.snapd.manage-interfaces" 88 ) 89 90 // userFromRequest extracts user information from request and return the respective user in state, if valid 91 // It requires the state to be locked 92 func userFromRequest(st *state.State, req *http.Request) (*auth.UserState, error) { 93 // extract macaroons data from request 94 header := req.Header.Get("Authorization") 95 if header == "" { 96 return nil, auth.ErrInvalidAuth 97 } 98 99 authorizationData := strings.SplitN(header, " ", 2) 100 if len(authorizationData) != 2 || authorizationData[0] != "Macaroon" { 101 return nil, fmt.Errorf("authorization header misses Macaroon prefix") 102 } 103 104 var macaroon string 105 var discharges []string 106 for _, field := range strutil.CommaSeparatedList(authorizationData[1]) { 107 if strings.HasPrefix(field, `root="`) { 108 macaroon = strings.TrimSuffix(field[6:], `"`) 109 } 110 if strings.HasPrefix(field, `discharge="`) { 111 discharges = append(discharges, strings.TrimSuffix(field[11:], `"`)) 112 } 113 } 114 115 if macaroon == "" { 116 return nil, fmt.Errorf("invalid authorization header") 117 } 118 119 user, err := auth.CheckMacaroon(st, macaroon, discharges) 120 return user, err 121 } 122 123 var muxVars = mux.Vars 124 125 func storeFrom(d *Daemon) snapstate.StoreService { 126 st := d.overlord.State() 127 st.Lock() 128 defer st.Unlock() 129 130 return snapstate.Store(st, nil) 131 } 132 133 var ( 134 snapstateInstall = snapstate.Install 135 snapstateInstallPath = snapstate.InstallPath 136 snapstateRefreshCandidates = snapstate.RefreshCandidates 137 snapstateTryPath = snapstate.TryPath 138 snapstateUpdate = snapstate.Update 139 snapstateUpdateMany = snapstate.UpdateMany 140 snapstateInstallMany = snapstate.InstallMany 141 snapstateRemoveMany = snapstate.RemoveMany 142 snapstateRevert = snapstate.Revert 143 snapstateRevertToRevision = snapstate.RevertToRevision 144 snapstateSwitch = snapstate.Switch 145 146 assertstateRefreshSnapDeclarations = assertstate.RefreshSnapDeclarations 147 ) 148 149 func ensureStateSoonImpl(st *state.State) { 150 st.EnsureBefore(0) 151 } 152 153 var ensureStateSoon = ensureStateSoonImpl 154 155 func newChange(st *state.State, kind, summary string, tsets []*state.TaskSet, snapNames []string) *state.Change { 156 chg := st.NewChange(kind, summary) 157 for _, ts := range tsets { 158 chg.AddAll(ts) 159 } 160 if snapNames != nil { 161 chg.Set("snap-names", snapNames) 162 } 163 return chg 164 } 165 166 func isTrue(form *multipart.Form, key string) bool { 167 value := form.Value[key] 168 if len(value) == 0 { 169 return false 170 } 171 b, err := strconv.ParseBool(value[0]) 172 if err != nil { 173 return false 174 } 175 176 return b 177 }