mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-21 05:58:13 +02:00
Chiffrement : les résultats d'outils et les images du fil suivent la mémoire
Les deux reprises d'AJEAN arrivées en parallèle du chiffrement écrivaient en clair à côté de discussions chiffrées. - Résultats complets des outils (« voir plus ») : bucket toolres ajouté à encryptedBuckets, écrits et relus par putStoreBytes / getStoreBytesErr. Mémoire verrouillée : rien n'est écrit, le flux porte le résultat entier. Le nettoyage des orphelins ne tourne plus quand la mémoire est verrouillée : l'index des discussions revenait vide et TOUT passait pour orphelin. - Images du fil (chatimg/) : même enveloppe que les pages mémoire ; verrouillée, l'image reste en base64 dans le message. Elles n'étaient jamais effacées : comme un fil rechargé perd ses images (stripImageParts), celles de plus de 24 h partent au démarrage et à chaque bascule de discussion. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ae0e181711
commit
58c2da1302
6 files changed
+133
-7
No files matched your search
@@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// chat_images.go — images d'une conversation stockées PAR RÉFÉRENCE.
|
||||
@@ -43,8 +44,14 @@ func storeChatImage(b []byte, mime string) (string, error) {
|
||||
}
|
||||
p := filepath.Join(dir, name)
|
||||
if _, err := os.Stat(p); err != nil {
|
||||
// Chiffrée comme le fil quand la mémoire l'est (même enveloppe que les
|
||||
// pages). Verrouillée : refus, l'image reste en base64 dans le message.
|
||||
enc, err := encodeMemContent(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmp := p + ".tmp"
|
||||
if err := os.WriteFile(tmp, b, 0o600); err != nil {
|
||||
if err := os.WriteFile(tmp, enc, 0o600); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := os.Rename(tmp, p); err != nil {
|
||||
@@ -76,7 +83,11 @@ func chatImageDataURL(ref string) (string, bool) {
|
||||
return u, true
|
||||
}
|
||||
imgCacheMu.Unlock()
|
||||
b, err := os.ReadFile(filepath.Join(chatImgDir(), name))
|
||||
raw, err := os.ReadFile(filepath.Join(chatImgDir(), name))
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
b, err := decodeMemContent(raw)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
@@ -103,6 +114,31 @@ func chatImageDataURL(ref string) (string, bool) {
|
||||
return u, true
|
||||
}
|
||||
|
||||
// chatImgKeep : âge minimal d'une image avant qu'on puisse l'effacer.
|
||||
const chatImgKeep = 24 * time.Hour
|
||||
|
||||
// pruneChatImages efface les images de plus de chatImgKeep. Appelée au
|
||||
// démarrage et à chaque bascule de discussion, c'est-à-dire quand le fil
|
||||
// vivant vient d'être rechargé — et stripImageParts retire les images d'un fil
|
||||
// rechargé : plus rien ne référence alors les fichiers. Le délai couvre un
|
||||
// fil resté ouvert longtemps sans bascule.
|
||||
func pruneChatImages() {
|
||||
dir := chatImgDir()
|
||||
entries, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cutoff := time.Now().Add(-chatImgKeep)
|
||||
for _, e := range entries {
|
||||
if e.IsDir() {
|
||||
continue
|
||||
}
|
||||
if info, err := e.Info(); err == nil && info.ModTime().Before(cutoff) {
|
||||
_ = os.Remove(filepath.Join(dir, e.Name()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// contentParts renvoie les parties d'un contenu multimodal, sous l'une ou l'autre
|
||||
// forme (fraîche []map, ou relue du JSON []any).
|
||||
func contentParts(content any) []map[string]any {
|
||||
|
||||
Reference in new issue
Block a user