github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/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  }