|
|
@@ -1,3 +1,5 @@
|
|
|
+// emoji_favorites.go handles persistence of the user's favorite emoji list,
|
|
|
+// stored as a JSON file in the cache directory.
|
|
|
package chat
|
|
|
|
|
|
import (
|
|
|
@@ -12,6 +14,12 @@ import (
|
|
|
|
|
|
const maxFavoriteEmoji = 10
|
|
|
|
|
|
+// maxFavoritesFileSize is the upper bound on the emoji favorites JSON file (4 KiB).
|
|
|
+const maxFavoritesFileSize = 4096
|
|
|
+
|
|
|
+// maxFavoriteEmojiLen is the maximum byte length of a single emoji favorite string.
|
|
|
+const maxFavoriteEmojiLen = 64
|
|
|
+
|
|
|
type emojiFavorites struct {
|
|
|
Favorites []string `json:"favorites"`
|
|
|
mu sync.RWMutex
|
|
|
@@ -25,35 +33,46 @@ func loadEmojiFavorites() *emojiFavorites {
|
|
|
if err != nil {
|
|
|
return ef
|
|
|
}
|
|
|
+ if len(data) > maxFavoritesFileSize {
|
|
|
+ slog.Warn("emoji favorites file too large, ignoring", "size", len(data))
|
|
|
+ return ef
|
|
|
+ }
|
|
|
if err := json.Unmarshal(data, ef); err != nil {
|
|
|
slog.Warn("failed to parse emoji favorites", "err", err)
|
|
|
return &emojiFavorites{}
|
|
|
}
|
|
|
+ // Reject any favorite strings that exceed the length limit.
|
|
|
+ valid := ef.Favorites[:0]
|
|
|
+ for _, e := range ef.Favorites {
|
|
|
+ if len(e) <= maxFavoriteEmojiLen {
|
|
|
+ valid = append(valid, e)
|
|
|
+ } else {
|
|
|
+ slog.Warn("emoji favorite too long, skipping", "len", len(e))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ef.Favorites = valid
|
|
|
return ef
|
|
|
}
|
|
|
|
|
|
+// save persists favorites to disk. The caller must hold ef.mu.
|
|
|
func (ef *emojiFavorites) save() {
|
|
|
- ef.mu.RLock()
|
|
|
- defer ef.mu.RUnlock()
|
|
|
atomicSaveJSON(emojiFavoritesPath, ef)
|
|
|
}
|
|
|
|
|
|
func (ef *emojiFavorites) toggle(emoji string) {
|
|
|
ef.mu.Lock()
|
|
|
+ defer ef.mu.Unlock()
|
|
|
for i, e := range ef.Favorites {
|
|
|
if e == emoji {
|
|
|
ef.Favorites = append(ef.Favorites[:i], ef.Favorites[i+1:]...)
|
|
|
- ef.mu.Unlock()
|
|
|
ef.save()
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
if len(ef.Favorites) >= maxFavoriteEmoji {
|
|
|
- ef.mu.Unlock()
|
|
|
return
|
|
|
}
|
|
|
ef.Favorites = append(ef.Favorites, emoji)
|
|
|
- ef.mu.Unlock()
|
|
|
ef.save()
|
|
|
}
|
|
|
|