package entries import ( "errors" "maxwarden/query" "maxwarden/security" "maxwarden/users" "sort" "strings" "time" "github.com/google/uuid" ) type Secret struct { ID string Description string URL string Notes string Username string Password string Created time.Time Modified time.Time } type EntryFilter struct { Filter query.Filter MasterKey string UserId int32 } func OrderByDescription(secret []Secret, desc bool) []Secret { sort.Slice(secret, func(i, j int) bool { if desc { return strings.ToLower(secret[i].Description) > strings.ToLower(secret[j].Description) } else { return strings.ToLower(secret[i].Description) < strings.ToLower(secret[j].Description) } }) return secret } func Filter(f EntryFilter) ([]Secret, error) { user, _ := users.FetchById(f.UserId) // we need to do the rest in memory because the data is encrypted, so we need to decrypt the data secrets, decErr := security.DecryptData[[]Secret](user.Data, f.MasterKey) if decErr != nil { return nil, decErr } if secrets == nil { return nil, errors.New("secrets list is null") } output := []Secret{} // decrypt data inside each entry retrieved for _, v := range *secrets { search := f.Filter.Search["description"] if search != "" { search = strings.ToLower(search) searchable := strings.ToLower(v.Description) if strings.Contains(searchable, search) { output = append(output, v) } } else { output = append(output, v) } } //order by output = OrderByDescription(output, f.Filter.OrderDescending) // pagination output = query.PaginateSlice(output, f.Filter) return output, nil } // linear search because that's the only option func FetchSecretFromID(userId int32, masterKey string, secretId string) (Secret, error) { user, _ := users.FetchById(userId) secrets, decErr := security.DecryptData[[]Secret](user.Data, masterKey) if decErr != nil { return Secret{}, decErr } if secrets == nil { return Secret{}, errors.New("secrets are nil") } for _, v := range *secrets { if v.ID == secretId { return v, nil } } return Secret{}, errors.New("no secret found") } func DeleteSecret(userId int32, masterKey string, secretId string) error { user, _ := users.FetchById(userId) secrets, decErr := security.DecryptData[[]Secret](user.Data, masterKey) if decErr != nil { return decErr } if secrets == nil { return errors.New("attempt to range over null secret array") } output := []Secret{} for _, v := range *secrets { if v.ID != secretId { output = append(output, v) } } enc, _ := security.EncryptData(&output, masterKey) user.Data = enc _, userErr := users.Update(user) return userErr } func Update(userId int32, masterKey string, secret Secret) error { user, _ := users.FetchById(userId) secrets, _ := security.DecryptData[[]Secret](user.Data, masterKey) if secrets == nil { return errors.New("user secrets are null") } secret.Modified = time.Now() // linear search and replace for i, v := range *secrets { if v.ID == secret.ID { created := (*secrets)[i].Created secret.Created = created (*secrets)[i] = secret } } enc, _ := security.EncryptData(secrets, masterKey) user.Data = enc _, updateErr := users.Update(user) return updateErr } func Add(userId int32, masterKey string, secret Secret) error { user, _ := users.FetchById(userId) secrets, _ := security.DecryptData[[]Secret](user.Data, masterKey) if secrets == nil { return errors.New("user secrets are null") } secret.ID = uuid.New().String() secret.Modified = time.Now() secret.Created = time.Now() *secrets = append(*secrets, secret) enc, _ := security.EncryptData(secrets, masterKey) user.Data = enc _, updateErr := users.Update(user) return updateErr }