From 6423d83949a5188e30786f762f59abf2f6483572 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Tue, 9 Jan 2024 15:08:11 +1100 Subject: [PATCH] implement delete secret --- controllers/store_secrets.go | 95 ++++++++++++++++++++---------------- models/secret.go | 52 ++++++++++++++++---- 2 files changed, 94 insertions(+), 53 deletions(-) diff --git a/controllers/store_secrets.go b/controllers/store_secrets.go index c4d678f..65bce75 100644 --- a/controllers/store_secrets.go +++ b/controllers/store_secrets.go @@ -293,9 +293,6 @@ func UpdateSecret(c *gin.Context) { } if len(secretList) == 0 { - - // TODO - also check secrets allowed for user - c.JSON(http.StatusBadRequest, gin.H{"error": "no secret matching search parameters"}) return } else if len(secretList) == 1 { @@ -339,77 +336,89 @@ func UpdateSecret(c *gin.Context) { func DeleteSecret(c *gin.Context) { var err error var input SecretInput - var UserId int + var user_id int if err := c.ShouldBindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid JSON received : " + err.Error()}) + c.JSON(http.StatusBadRequest, gin.H{"error": "DeleteSecret error binding to input JSON : " + err.Error()}) return } - // Input validation - if input.DeviceCategory == "" && input.DeviceName == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "cannot store secret with empty deviceName and empty deviceCategory"}) + log.Printf("DeleteSecret received JSON input '%v'\n", input) + + if len(input.SecretValue) == 0 { + errString := "DeleteSecret no updated secret specified\n" + log.Print(errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) return } + // Temporarily disable because we should be able to figure it out without user specifying /* if input.SafeId == 0 && len(input.SafeName) == 0 { - errString := "StoreSecret no safe specified\n" + errString := "UpdateSecret no safe specified\n" log.Print(errString) c.JSON(http.StatusBadRequest, gin.H{"error": errString}) return } */ - // Don't log this since it contains plaintext secrets - //log.Printf("StoreSecret received JSON input '%v'\n", input) - - // Populate fields - s := models.Secret{} - s.UserName = input.UserName - s.DeviceName = input.DeviceName - s.DeviceCategory = input.DeviceCategory - - // Query which safes the current user is allowed to access - /* - user_id, err := token.ExtractTokenID(c) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "error determining user"}) - return - } - */ - // Get userId that we stored in the context earlier if val, ok := c.Get("user-id"); !ok { c.JSON(http.StatusBadRequest, gin.H{"error": "error determining user"}) return } else { - UserId = val.(int) + user_id = val.(int) //log.Printf("user_id: %v\n", user_id) } - safeId, err := FindSafeId(UserId, input) + // Populate fields + s := models.Secret{} + + s.UserName = input.UserName + s.DeviceName = input.DeviceName + s.DeviceCategory = input.DeviceCategory + + secretList, err := models.SecretsGetAllowed(&s, user_id) if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + errString := fmt.Sprintf("error getting allowed secrets : '%s'", err) + log.Printf("DeleteSecret %s\n", errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) return } - s.SafeId = safeId - // If this secret already exists in the database then generate an error - checkExists, err := models.GetSecrets(&s, false) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + if len(secretList) == 0 { + errString := "no secret matching search parameters" + log.Printf("DeleteSecret %s\n", errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) return - } - if len(checkExists) == 0 { - c.JSON(http.StatusBadRequest, gin.H{"error": "no secrets matched search parameters"}) - return - } else if len(checkExists) == 1 { - c.JSON(http.StatusOK, gin.H{"message": "mock secret deleted successfully"}) + } else if len(secretList) == 1 { + // Delete secret + log.Printf("secretList[0]: %v\n", secretList[0]) - // TODO delete secret + s.SecretId = secretList[0].SecretId + + // check for empty fields in the update request and update from the existing record + if s.UserName == "" { + s.UserName = secretList[0].Secret.UserName + } + if s.DeviceCategory == "" { + s.DeviceCategory = secretList[0].DeviceCategory + } + if s.DeviceName == "" { + s.DeviceName = secretList[0].DeviceName + } + + _, err = s.DeleteSecret() + if err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "DeleteSecret error deleting secret : " + err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"message": "secret deleted successfully"}) } else { - c.JSON(http.StatusBadRequest, gin.H{"error": "multiple secrets matched search parameters, be more specific"}) + errString := "multiple secrets matched search parameters, be more specific" + log.Printf("DeleteSecret %s\n", errString) + c.JSON(http.StatusBadRequest, gin.H{"error": errString}) return } } diff --git a/models/secret.go b/models/secret.go index 18f46b1..cc50261 100644 --- a/models/secret.go +++ b/models/secret.go @@ -95,7 +95,8 @@ func SecretsGetAllowed(s *Secret, userId int) ([]UserSecret, error) { } // Query for user access - query += `UNION + query += ` + UNION SELECT users.UserId, users.GroupId, permissions.ReadOnly, permissions.SafeId, safes.SafeName, secrets.* FROM users INNER JOIN permissions ON users.UserId = permissions.UserId @@ -137,16 +138,20 @@ func SecretsGetAllowed(s *Secret, userId int) ([]UserSecret, error) { return secretResults, err } - // Decrypt the secret - _, err = r.DecryptSecret() - if err != nil { - //log.Printf("GetSecret unable to decrypt stored secret '%v' : '%s'\n", r.Secret, err) - log.Printf("SecretsGetAllowedForGroup unable to decrypt stored secret : '%s'\n", err) - return secretResults, err - } else { - secretResults = append(secretResults, r) - } + /* + // Decrypt the secret + _, err = r.DecryptSecret() + if err != nil { + //log.Printf("GetSecret unable to decrypt stored secret '%v' : '%s'\n", r.Secret, err) + log.Printf("SecretsGetAllowedForGroup unable to decrypt stored secret : '%s'\n", err) + return secretResults, err + } else { + secretResults = append(secretResults, r) + } + */ + // Don't decrypt the secrets in the results of this query + secretResults = append(secretResults, r) } log.Printf("SecretsGetAllowedForGroup retrieved '%d' results\n", len(secretResults)) } @@ -154,6 +159,7 @@ func SecretsGetAllowed(s *Secret, userId int) ([]UserSecret, error) { return secretResults, nil } +/* func SecretsSearchAllSafes(s *Secret) ([]Secret, error) { var err error var secretResults []Secret @@ -217,6 +223,7 @@ func SecretsSearchAllSafes(s *Secret) ([]Secret, error) { return secretResults, nil } +*/ // SecretsGetMultipleSafes queries the specified safes for matching secrets func SecretsGetMultipleSafes(s *Secret, safeIds []int) ([]Secret, error) { @@ -415,6 +422,31 @@ func (s *Secret) UpdateSecret() (*Secret, error) { return s, nil } +func (s *Secret) DeleteSecret() (*Secret, error) { + + var err error + + log.Printf("DeleteSecret deleting record with values '%v'\n", s) + + if s.SecretId == 0 { + err = errors.New("unable to locate secret with empty secretId field") + log.Printf("DeleteSecret error in pre-check : '%s'\n", err) + return s, err + } + + result, err := db.NamedExec((`DELETE FROM secrets WHERE SecretId = :SecretId`), s) + if err != nil { + log.Printf("DeleteSecret error executing sql record : '%s'\n", err) + return &Secret{}, err + } else { + affected, _ := result.RowsAffected() + id, _ := result.LastInsertId() + log.Printf("DeleteSecret delete returned result id '%d' affecting %d row(s).\n", id, affected) + } + + return s, nil +} + // startCipher does the initial setup of the AES256 GCM mode cipher func startCipher() (cipher.AEAD, error) { key, err := ProvideKey()