Просмотр исходного кода

Merge worktree-agent-a0fed213 into master

claude 1 месяц назад
Родитель
Сommit
330861c33f
2 измененных файлов с 16 добавлено и 7 удалено
  1. 10 4
      internal/notifications/notifications.go
  2. 6 3
      internal/ui/chat/attachment_handler.go

+ 10 - 4
internal/notifications/notifications.go

@@ -5,6 +5,7 @@ import (
 	"io"
 	"io"
 	"log/slog"
 	"log/slog"
 	"net/http"
 	"net/http"
+	neturl "net/url"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"time"
 	"time"
@@ -88,11 +89,10 @@ func getCachedProfileImage(avatarHash discord.Hash, url string) (string, error)
 		return path, nil
 		return path, nil
 	}
 	}
 
 
-	file, err := os.Create(path)
-	if err != nil {
-		return "", err
+	parsed, err := neturl.Parse(url)
+	if err != nil || parsed.Scheme != "https" {
+		return "", fmt.Errorf("refusing non-HTTPS avatar URL")
 	}
 	}
-	defer file.Close()
 
 
 	resp, err := avatarHTTPClient.Get(url)
 	resp, err := avatarHTTPClient.Get(url)
 	if err != nil {
 	if err != nil {
@@ -104,6 +104,12 @@ func getCachedProfileImage(avatarHash discord.Hash, url string) (string, error)
 		return "", fmt.Errorf("unexpected status %d fetching avatar", resp.StatusCode)
 		return "", fmt.Errorf("unexpected status %d fetching avatar", resp.StatusCode)
 	}
 	}
 
 
+	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
+	if err != nil {
+		return "", err
+	}
+	defer file.Close()
+
 	if _, err := io.Copy(file, io.LimitReader(resp.Body, 10*1024*1024)); err != nil {
 	if _, err := io.Copy(file, io.LimitReader(resp.Body, 10*1024*1024)); err != nil {
 		return "", err
 		return "", err
 	}
 	}

+ 6 - 3
internal/ui/chat/attachment_handler.go

@@ -11,6 +11,7 @@ import (
 	"path/filepath"
 	"path/filepath"
 	"runtime"
 	"runtime"
 	"strings"
 	"strings"
+	"time"
 
 
 	"github.com/ayn2op/discordo/internal/consts"
 	"github.com/ayn2op/discordo/internal/consts"
 	"github.com/ayn2op/discordo/internal/ui"
 	"github.com/ayn2op/discordo/internal/ui"
@@ -20,6 +21,8 @@ import (
 
 
 const maxAttachmentSize = 100 * 1024 * 1024 // 100 MB
 const maxAttachmentSize = 100 * 1024 * 1024 // 100 MB
 
 
+var attachmentHTTPClient = &http.Client{Timeout: 30 * time.Second}
+
 func openDefault(target string) error {
 func openDefault(target string) error {
 	var cmd *exec.Cmd
 	var cmd *exec.Cmd
 	switch runtime.GOOS {
 	switch runtime.GOOS {
@@ -49,7 +52,7 @@ func (ml *messagesList) downloadToCache(attachment discord.Attachment) (string,
 		return "", fmt.Errorf("refusing non-HTTPS attachment URL: %s", parsed.Scheme)
 		return "", fmt.Errorf("refusing non-HTTPS attachment URL: %s", parsed.Scheme)
 	}
 	}
 
 
-	resp, err := http.Get(attachment.URL)
+	resp, err := attachmentHTTPClient.Get(attachment.URL)
 	if err != nil {
 	if err != nil {
 		return "", fmt.Errorf("failed to fetch attachment: %w", err)
 		return "", fmt.Errorf("failed to fetch attachment: %w", err)
 	}
 	}
@@ -69,7 +72,7 @@ func (ml *messagesList) downloadToCache(attachment discord.Attachment) (string,
 		safeName = "attachment"
 		safeName = "attachment"
 	}
 	}
 	path := filepath.Join(dir, safeName)
 	path := filepath.Join(dir, safeName)
-	file, err := os.Create(path)
+	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
 	if err != nil {
 	if err != nil {
 		return "", fmt.Errorf("failed to create attachment file: %w", err)
 		return "", fmt.Errorf("failed to create attachment file: %w", err)
 	}
 	}
@@ -184,7 +187,7 @@ func (ml *messagesList) saveAttachmentImage(attachment discord.Attachment) {
 	}
 	}
 	defer src.Close()
 	defer src.Close()
 
 
-	dst, err := os.Create(destPath)
+	dst, err := os.OpenFile(destPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600)
 	if err != nil {
 	if err != nil {
 		slog.Error("failed to create save file", "err", err, "path", destPath)
 		slog.Error("failed to create save file", "err", err, "path", destPath)
 		return
 		return