github.com/stolowski/snapd@v0.0.0-20210407085831-115137ce5a22/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 } 81 82 // userFromRequest extracts user information from request and return the respective user in state, if valid 83 // It requires the state to be locked 84 func userFromRequest(st *state.State, req *http.Request) (*auth.UserState, error) { 85 // extract macaroons data from request 86 header := req.Header.Get("Authorization") 87 if header == "" { 88 return nil, auth.ErrInvalidAuth 89 } 90 91 authorizationData := strings.SplitN(header, " ", 2) 92 if len(authorizationData) != 2 || authorizationData[0] != "Macaroon" { 93 return nil, fmt.Errorf("authorization header misses Macaroon prefix") 94 } 95 96 var macaroon string 97 var discharges []string 98 for _, field := range strutil.CommaSeparatedList(authorizationData[1]) { 99 if strings.HasPrefix(field, `root="`) { 100 macaroon = strings.TrimSuffix(field[6:], `"`) 101 } 102 if strings.HasPrefix(field, `discharge="`) { 103 discharges = append(discharges, strings.TrimSuffix(field[11:], `"`)) 104 } 105 } 106 107 if macaroon == "" { 108 return nil, fmt.Errorf("invalid authorization header") 109 } 110 111 user, err := auth.CheckMacaroon(st, macaroon, discharges) 112 return user, err 113 } 114 115 var muxVars = mux.Vars 116 117 func storeFrom(d *Daemon) snapstate.StoreService { 118 st := d.overlord.State() 119 st.Lock() 120 defer st.Unlock() 121 122 return snapstate.Store(st, nil) 123 } 124 125 var ( 126 snapstateInstall = snapstate.Install 127 snapstateInstallPath = snapstate.InstallPath 128 snapstateRefreshCandidates = snapstate.RefreshCandidates 129 snapstateTryPath = snapstate.TryPath 130 snapstateUpdate = snapstate.Update 131 snapstateUpdateMany = snapstate.UpdateMany 132 snapstateInstallMany = snapstate.InstallMany 133 snapstateRemoveMany = snapstate.RemoveMany 134 snapstateRevert = snapstate.Revert 135 snapstateRevertToRevision = snapstate.RevertToRevision 136 snapstateSwitch = snapstate.Switch 137 138 assertstateRefreshSnapDeclarations = assertstate.RefreshSnapDeclarations 139 ) 140 141 func ensureStateSoonImpl(st *state.State) { 142 st.EnsureBefore(0) 143 } 144 145 var ensureStateSoon = ensureStateSoonImpl 146 147 func newChange(st *state.State, kind, summary string, tsets []*state.TaskSet, snapNames []string) *state.Change { 148 chg := st.NewChange(kind, summary) 149 for _, ts := range tsets { 150 chg.AddAll(ts) 151 } 152 if snapNames != nil { 153 chg.Set("snap-names", snapNames) 154 } 155 return chg 156 } 157 158 func isTrue(form *multipart.Form, key string) bool { 159 value := form.Value[key] 160 if len(value) == 0 { 161 return false 162 } 163 b, err := strconv.ParseBool(value[0]) 164 if err != nil { 165 return false 166 } 167 168 return b 169 }