// NewUser tracks a new authenticated user and saves its details in the state func NewUser(st *state.State, username, macaroon string, discharges []string) (*UserState, error) { var authStateData AuthState err := st.Get("auth", &authStateData) if err == state.ErrNoState { authStateData = AuthState{} } else if err != nil { return nil, err } sort.Strings(discharges) authStateData.LastID++ authenticatedUser := UserState{ ID: authStateData.LastID, Username: username, Macaroon: macaroon, Discharges: discharges, StoreMacaroon: macaroon, StoreDischarges: discharges, } authStateData.Users = append(authStateData.Users, authenticatedUser) st.Set("auth", authStateData) return &authenticatedUser, nil }
// CheckMacaroon returns the UserState for the given macaroon/discharges credentials func CheckMacaroon(st *state.State, macaroon string, discharges []string) (*UserState, error) { var authStateData AuthState err := st.Get("auth", &authStateData) if err != nil { return nil, ErrInvalidAuth } NextUser: for _, user := range authStateData.Users { if user.Macaroon != macaroon { continue } if len(user.Discharges) != len(discharges) { continue } // sort discharges (stored users' discharges are already sorted) sort.Strings(discharges) for i, d := range user.Discharges { if d != discharges[i] { continue NextUser } } return &user, nil } return nil, ErrInvalidAuth }
func getConns(st *state.State) (map[string]connState, error) { // Get information about connections from the state var conns map[string]connState err := st.Get("conns", &conns) if err != nil && err != state.ErrNoState { return nil, fmt.Errorf("cannot obtain data about existing connections: %s", err) } if conns == nil { conns = make(map[string]connState) } return conns, nil }
// User returns a user from the state given its ID func User(st *state.State, id int) (*UserState, error) { var authStateData AuthState err := st.Get("auth", &authStateData) if err != nil { return nil, err } for _, user := range authStateData.Users { if user.ID == id { return &user, nil } } return nil, fmt.Errorf("invalid user") }
// All retrieves return a map from name to SnapState for all current snaps in the system state. func All(s *state.State) (map[string]*SnapState, error) { // XXX: result is a map because sideloaded snaps carry no name // atm in their sideinfos var stateMap map[string]*SnapState if err := s.Get("snaps", &stateMap); err != nil && err != state.ErrNoState { return nil, err } curStates := make(map[string]*SnapState, len(stateMap)) for snapName, snapState := range stateMap { if snapState.Current() != nil { curStates[snapName] = snapState } } return curStates, nil }
// Get retrieves the SnapState of the given snap. func Get(s *state.State, name string, snapst *SnapState) error { var snaps map[string]*json.RawMessage err := s.Get("snaps", &snaps) if err != nil { return err } raw, ok := snaps[name] if !ok { return state.ErrNoState } err = json.Unmarshal([]byte(*raw), &snapst) if err != nil { return fmt.Errorf("cannot unmarshal snap state: %v", err) } return nil }
// ActiveInfos returns information about all active snaps. func ActiveInfos(s *state.State) ([]*snap.Info, error) { var stateMap map[string]*SnapState var infos []*snap.Info if err := s.Get("snaps", &stateMap); err != nil && err != state.ErrNoState { return nil, err } for snapName, snapState := range stateMap { if !snapState.Active { continue } snapInfo, err := readInfo(snapName, snapState.Current()) if err != nil { logger.Noticef("cannot retrieve info for snap %q: %s", snapName, err) continue } infos = append(infos, snapInfo) } return infos, nil }
// Set sets the SnapState of the given snap, overwriting any earlier state. func Set(s *state.State, name string, snapst *SnapState) { var snaps map[string]*json.RawMessage err := s.Get("snaps", &snaps) if err != nil && err != state.ErrNoState { panic("internal error: cannot unmarshal snaps state: " + err.Error()) } if snaps == nil { snaps = make(map[string]*json.RawMessage) } if snapst == nil || (len(snapst.Sequence) == 0 && snapst.Candidate == nil) { delete(snaps, name) } else { data, err := json.Marshal(snapst) if err != nil { panic("internal error: cannot marshal snap state: " + err.Error()) } raw := json.RawMessage(data) snaps[name] = &raw } s.Set("snaps", snaps) }
// RemoveUser removes a user from the state given its ID func RemoveUser(st *state.State, userID int) error { var authStateData AuthState err := st.Get("auth", &authStateData) if err != nil { return err } for i := range authStateData.Users { if authStateData.Users[i].ID == userID { // delete without preserving order n := len(authStateData.Users) - 1 authStateData.Users[i] = authStateData.Users[n] authStateData.Users[n] = UserState{} authStateData.Users = authStateData.Users[:n] st.Set("auth", authStateData) return nil } } return fmt.Errorf("invalid user") }