// UpdateFromJSON updates a user from a JSON object, carrying out a bunch of // validations inside. func (u *User) UpdateFromJSON(jsonUser map[string]interface{}) util.Gerror { userName, nerr := util.ValidateAsString(jsonUser["name"]) if nerr != nil { return nerr } if u.Username != userName { err := util.Errorf("User name %s and %s from JSON do not match", u.Username, userName) return err } /* Validations. */ /* Invalid top level elements */ validElements := []string{"username", "name", "org_name", "public_key", "private_key", "admin", "password", "email", "salt"} ValidElem: for k := range jsonUser { for _, i := range validElements { if k == i { continue ValidElem } } err := util.Errorf("Invalid key %s in request body", k) return err } var verr util.Gerror // Check the password first. If it's bad, bail before touching anything // else. if passwd, ok := jsonUser["password"]; ok { passwd, verr = util.ValidateAsString(passwd) if verr != nil { return verr } if passwd != "" { verr = u.SetPasswd(passwd.(string)) if verr != nil { return verr } } } if adminVal, ok := jsonUser["admin"]; ok { var ab bool if ab, verr = util.ValidateAsBool(adminVal); verr != nil { // NOTE: may need to tweak this error message depending // if this is a user or a client verr = util.Errorf("Field 'admin' invalid") return verr } else if u.Admin && !ab { if u.isLastAdmin() { verr = util.Errorf("Cannot remove admin status from the last admin") verr.SetStatus(http.StatusForbidden) return verr } } u.Admin = ab } return nil }
// CheckPermEdit checks to see if the user is trying to edit admin and // validator attributes, and if it has permissions to do so. func (u *User) CheckPermEdit(userData map[string]interface{}, perm string) util.Gerror { gerr := util.Errorf("You are not allowed to take this action.") gerr.SetStatus(http.StatusForbidden) if av, ok := userData[perm]; ok { if a, _ := util.ValidateAsBool(av); a { return gerr } } return nil }
// UpdateVersion updates a specific version of a cookbook. func (cbv *CookbookVersion) UpdateVersion(cbvData map[string]interface{}, force string) util.Gerror { /* Allow force to update a frozen cookbook */ if cbv.IsFrozen == true && force != "true" { err := util.Errorf("The cookbook %s at version %s is frozen. Use the 'force' option to override.", cbv.CookbookName, cbv.Version) err.SetStatus(http.StatusConflict) return err } fhashes := cbv.fileHashes() _, nerr := util.ValidateAsString(cbvData["cookbook_name"]) if nerr != nil { if nerr.Error() == "Field 'name' missing" { nerr = util.Errorf("Field 'cookbook_name' missing") } else { nerr = util.Errorf("Field 'cookbook_name' invalid") } return nerr } /* Validation, validation, all is validation. */ validElements := []string{"cookbook_name", "name", "version", "json_class", "chef_type", "definitions", "libraries", "attributes", "recipes", "providers", "resources", "templates", "root_files", "files", "frozen?", "metadata", "force"} ValidElem: for k := range cbvData { for _, i := range validElements { if k == i { continue ValidElem } } err := util.Errorf("Invalid key %s in request body", k) return err } var verr util.Gerror cbvData["chef_type"], verr = util.ValidateAsFieldString(cbvData["chef_type"]) if verr != nil { if verr.Error() == "Field 'name' nil" { cbvData["chef_type"] = cbv.ChefType } else { verr = util.Errorf("Field 'chef_type' invalid") return verr } } else { // Wait, what was I doing here? // if !util.ValidateEnvName(cbvData["chef_type"].(string)) { if cbvData["chef_type"].(string) != "cookbook_version" { verr = util.Errorf("Field 'chef_type' invalid") return verr } } cbvData["json_class"], verr = util.ValidateAsFieldString(cbvData["json_class"]) if verr != nil { if verr.Error() == "Field 'name' nil" { cbvData["json_class"] = cbv.JSONClass } else { verr = util.Errorf("Field 'json_class' invalid") return verr } } else { if cbvData["json_class"].(string) != "Chef::CookbookVersion" { verr = util.Errorf("Field 'json_class' invalid") return verr } } cbvData["version"], verr = util.ValidateAsVersion(cbvData["version"]) if verr != nil { verr = util.Errorf("Field 'version' invalid") return verr } if cbvData["version"].(string) == "0.0.0" && cbv.Version != "" { cbvData["version"] = cbv.Version } divs := []string{"definitions", "libraries", "attributes", "recipes", "providers", "resources", "templates", "root_files", "files"} for _, d := range divs { cbvData[d], verr = util.ValidateCookbookDivision(d, cbvData[d]) if verr != nil { return verr } } cbvData["metadata"], verr = util.ValidateCookbookMetadata(cbvData["metadata"]) if verr != nil { return verr } cbvData["frozen?"], verr = util.ValidateAsBool(cbvData["frozen?"]) if verr != nil { return verr } /* Basic sanity checking */ if cbvData["cookbook_name"].(string) != cbv.CookbookName { err := util.Errorf("Field 'cookbook_name' invalid") return err } if cbvData["name"].(string) != cbv.Name { err := util.Errorf("Field 'name' invalid") return err } if cbvData["version"].(string) != cbv.Version && cbvData["version"] != "0.0.0" { err := util.Errorf("Field 'version' invalid") return err } /* Update the data */ /* With these next two, should we test for existence before setting? */ cbv.ChefType = cbvData["chef_type"].(string) cbv.JSONClass = cbvData["json_class"].(string) cbv.Definitions = convertToCookbookDiv(cbvData["definitions"]) cbv.Libraries = convertToCookbookDiv(cbvData["libraries"]) cbv.Attributes = convertToCookbookDiv(cbvData["attributes"]) cbv.Recipes = cbvData["recipes"].([]map[string]interface{}) cbv.Providers = convertToCookbookDiv(cbvData["providers"]) cbv.Resources = convertToCookbookDiv(cbvData["resources"]) cbv.Templates = convertToCookbookDiv(cbvData["templates"]) cbv.RootFiles = convertToCookbookDiv(cbvData["root_files"]) cbv.Files = convertToCookbookDiv(cbvData["files"]) if cbv.IsFrozen != true { cbv.IsFrozen = cbvData["frozen?"].(bool) } cbv.Metadata = cbvData["metadata"].(map[string]interface{}) /* If we're using SQL, update this version in the DB. */ if config.UsingDB() { if err := cbv.updateCookbookVersionSQL(); err != nil { return err } } /* Clean cookbook hashes */ if len(fhashes) > 0 { // Get our parent. Bravely assuming that if it exists we exist. cbook, _ := Get(cbv.CookbookName) cbook.Versions[cbv.Version] = cbv cbook.deleteHashes(fhashes) } return nil }
// UpdateFromJSON updates a client/user from a json object. Does a bunch of // validations inside rather than in the handler. func (c *Client) UpdateFromJSON(jsonActor map[string]interface{}) util.Gerror { actorName, nerr := util.ValidateAsString(jsonActor["name"]) if nerr != nil { return nerr } if c.Name != actorName { err := util.Errorf("Client name %s and %s from JSON do not match", c.Name, actorName) return err } /* Validations. */ /* Invalid top level elements */ validElements := []string{"name", "json_class", "chef_type", "validator", "org_name", "orgname", "public_key", "private_key", "admin", "certificate", "password", "node_name"} ValidElem: for k := range jsonActor { for _, i := range validElements { if k == i { continue ValidElem } } err := util.Errorf("Invalid key %s in request body", k) return err } var verr util.Gerror jsonActor["json_class"], verr = util.ValidateAsFieldString(jsonActor["json_class"]) if verr != nil { if verr.Error() == "Field 'name' nil" { jsonActor["json_class"] = c.JSONClass } else { return verr } } else { if jsonActor["json_class"].(string) != "Chef::ApiClient" { verr = util.Errorf("Field 'json_class' invalid") return verr } } jsonActor["chef_type"], verr = util.ValidateAsFieldString(jsonActor["chef_type"]) if verr != nil { if verr.Error() == "Field 'name' nil" { jsonActor["chef_type"] = c.ChefType } else { return verr } } else { if jsonActor["chef_type"].(string) != "client" { verr = util.Errorf("Field 'chef_type' invalid") return verr } } var ab, vb bool if adminVal, ok := jsonActor["admin"]; ok { if ab, verr = util.ValidateAsBool(adminVal); verr != nil { // NOTE: may need to tweak this error message depending // if this is a user or a client verr = util.Errorf("Field 'admin' invalid") return verr } else if c.Admin && !ab { if c.isLastAdmin() { verr = util.Errorf("Cannot remove admin status from the last admin") verr.SetStatus(http.StatusForbidden) return verr } } } if validatorVal, ok := jsonActor["validator"]; ok { if vb, verr = util.ValidateAsBool(validatorVal); verr != nil { return verr } } if ab && vb { verr = util.Errorf("Client can be either an admin or a validator, but not both.") verr.SetStatus(http.StatusBadRequest) return verr } c.Admin = ab c.Validator = vb c.ChefType = jsonActor["chef_type"].(string) c.JSONClass = jsonActor["json_class"].(string) return nil }