diff --git a/pkg/channels/telegram/telegram.go b/pkg/channels/telegram/telegram.go index 580bfd634..1b45a36e7 100644 --- a/pkg/channels/telegram/telegram.go +++ b/pkg/channels/telegram/telegram.go @@ -47,12 +47,13 @@ var ( type TelegramChannel struct { *channels.BaseChannel - bot *telego.Bot - bh *th.BotHandler - config *config.Config - chatIDs map[string]int64 - ctx context.Context - cancel context.CancelFunc + bot *telego.Bot + bh *th.BotHandler + config *config.Config + chatIDs map[string]int64 + ctx context.Context + cancel context.CancelFunc + downloadC *tls.Config registerFunc func(context.Context, []commands.Definition) error commandRegCancel context.CancelFunc @@ -74,8 +75,6 @@ func NewTelegramChannel(cfg *config.Config, bus *bus.MessageBus) (*TelegramChann return nil, fmt.Errorf("invalid proxy URL %q: %w", telegramCfg.Proxy, parseErr) } transport.Proxy = http.ProxyURL(proxyURL) - } else { - transport.Proxy = http.ProxyFromEnvironment } if baseURL := strings.TrimRight(strings.TrimSpace(telegramCfg.BaseURL), "/"); baseURL != "" { @@ -103,15 +102,13 @@ func NewTelegramChannel(cfg *config.Config, bus *bus.MessageBus) (*TelegramChann bot: bot, config: cfg, chatIDs: make(map[string]int64), + downloadC: transport.TLSClientConfig, }, nil } func telegramHTTPTransport(cfg config.TelegramConfig) (*http.Transport, error) { - // Start with Go defaults, then inject proxy + TLS tweaks. - // We keep timeouts conservative; telego itself also applies request-level timeouts. - t := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - } + // Clone default transport to preserve Go's standard dial/TLS timeouts. + t := http.DefaultTransport.(*http.Transport).Clone() tlsCfg, err := telegramTLSConfig(cfg) if err != nil { @@ -127,6 +124,9 @@ func telegramTLSConfig(cfg config.TelegramConfig) (*tls.Config, error) { if !cfg.TLSInsecure && strings.TrimSpace(cfg.TLSCAFile) == "" && strings.TrimSpace(cfg.TLSCADir) == "" { return nil, nil } + if cfg.TLSInsecure { + logger.WarnC("telegram", "TLS verification is disabled via channels.telegram.tls_insecure") + } base, err := x509.SystemCertPool() if err != nil || base == nil { @@ -152,14 +152,19 @@ func telegramTLSConfig(cfg config.TelegramConfig) (*tls.Config, error) { if ent.IsDir() { continue } - // Common practice: read every file; ignore parse failures quietly to handle - // hashed symlinks / non-PEM files. p := filepath.Join(caDir, ent.Name()) b, e := os.ReadFile(p) if e != nil { continue } - _ = base.AppendCertsFromPEM(b) + if ok := base.AppendCertsFromPEM(b); !ok { + name := strings.ToLower(ent.Name()) + if strings.HasSuffix(name, ".pem") || strings.HasSuffix(name, ".crt") || strings.HasSuffix(name, ".cer") { + logger.WarnCF("telegram", "Failed to parse certificate file in tls_ca_dir", map[string]any{ + "path": p, + }) + } + } } } @@ -948,6 +953,8 @@ func (c *TelegramChannel) downloadFileWithInfo(file *telego.File, ext string) st filename := file.FilePath + ext return utils.DownloadFile(url, filename, utils.DownloadOptions{ LoggerPrefix: "telegram", + ProxyURL: c.config.Channels.Telegram.Proxy, + TLSConfig: c.downloadC, }) } diff --git a/pkg/config/config.go b/pkg/config/config.go index f3c86c636..3018d7b92 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -344,9 +344,9 @@ type TelegramConfig struct { Token SecureString `json:"token,omitzero" yaml:"token,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_TOKEN"` BaseURL string `json:"base_url" yaml:"-" env:"PICOCLAW_CHANNELS_TELEGRAM_BASE_URL"` Proxy string `json:"proxy" yaml:"-" env:"PICOCLAW_CHANNELS_TELEGRAM_PROXY"` - TLSCAFile string `json:"tls_ca_file,omitempty" yaml:"-" env:"PICOCLAW_CHANNELS_TELEGRAM_TLS_CA_FILE"` - TLSCADir string `json:"tls_ca_dir,omitempty" yaml:"-" env:"PICOCLAW_CHANNELS_TELEGRAM_TLS_CA_DIR"` - TLSInsecure bool `json:"tls_insecure,omitempty" yaml:"-" env:"PICOCLAW_CHANNELS_TELEGRAM_TLS_INSECURE"` + TLSCAFile string `json:"tls_ca_file,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_TLS_CA_FILE"` + TLSCADir string `json:"tls_ca_dir,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_TLS_CA_DIR"` + TLSInsecure bool `json:"tls_insecure,omitempty" env:"PICOCLAW_CHANNELS_TELEGRAM_TLS_INSECURE"` AllowFrom FlexibleStringSlice `json:"allow_from" yaml:"-" env:"PICOCLAW_CHANNELS_TELEGRAM_ALLOW_FROM"` GroupTrigger GroupTriggerConfig `json:"group_trigger,omitempty" yaml:"-"` Typing TypingConfig `json:"typing,omitempty" yaml:"-"` diff --git a/pkg/providers/github_copilot_provider.go b/pkg/providers/github_copilot_provider.go index e2d1d7d98..472c14257 100644 --- a/pkg/providers/github_copilot_provider.go +++ b/pkg/providers/github_copilot_provider.go @@ -41,9 +41,9 @@ func NewGitHubCopilotProvider(uri string, connectMode string, model string) (*Gi } session, err := client.CreateSession(context.Background(), &copilot.SessionConfig{ - Model: model, + Model: model, OnPermissionRequest: copilot.PermissionHandler.ApproveAll, - Hooks: &copilot.SessionHooks{}, + Hooks: &copilot.SessionHooks{}, }) if err != nil { client.Stop() diff --git a/pkg/utils/media.go b/pkg/utils/media.go index 823ca155e..e0dda1e71 100644 --- a/pkg/utils/media.go +++ b/pkg/utils/media.go @@ -1,6 +1,7 @@ package utils import ( + "crypto/tls" "fmt" "io" "net/http" @@ -68,6 +69,7 @@ type DownloadOptions struct { ExtraHeaders map[string]string LoggerPrefix string ProxyURL string + TLSConfig *tls.Config } // DownloadFile downloads a file from URL to a local temp directory. @@ -107,7 +109,10 @@ func DownloadFile(urlStr, filename string, opts DownloadOptions) string { req.Header.Set(key, value) } - client := &http.Client{Timeout: opts.Timeout} + transport := http.DefaultTransport.(*http.Transport).Clone() + if opts.TLSConfig != nil { + transport.TLSClientConfig = opts.TLSConfig + } if opts.ProxyURL != "" { proxyURL, parseErr := url.Parse(opts.ProxyURL) if parseErr != nil { @@ -117,10 +122,9 @@ func DownloadFile(urlStr, filename string, opts DownloadOptions) string { }) return "" } - client.Transport = &http.Transport{ - Proxy: http.ProxyURL(proxyURL), - } + transport.Proxy = http.ProxyURL(proxyURL) } + client := &http.Client{Timeout: opts.Timeout, Transport: transport} resp, err := client.Do(req) if err != nil { logger.ErrorCF(opts.LoggerPrefix, "Failed to download file", map[string]any{