diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6802d09 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,48 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone. + +## Our Standards + +Examples of behavior that contributes to a positive environment: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes + +Examples of unacceptable behavior: + +* The use of sexualized language or imagery +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information without explicit permission + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +https://github.com/y0sy4/tg-ws-proxy-go/issues + +All complaints will be reviewed and investigated promptly and fairly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), +version 2.1, available at +https://www.contributor-covenant.org/version/2/1/code_of_conduct.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..91744e0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,68 @@ +# Contributing to TG WS Proxy Go + +First off, thank you for considering contributing to TG WS Proxy Go! + +## How Can I Contribute? + +### Reporting Bugs + +Before creating bug reports, please check the existing issues as you might find out that you don't need to create one. When you are creating a bug report, please include as many details as possible: + +* **Use a clear and descriptive title** +* **Describe the exact steps to reproduce the problem** +* **Provide specific examples to demonstrate the steps** +* **Describe the behavior you observed and what behavior you expected** +* **Include logs if possible** (from %APPDATA%/TgWsProxy/proxy.log) + +### Suggesting Enhancements + +Enhancement suggestions are tracked as GitHub issues. When creating an enhancement suggestion, please include: + +* **Use a clear and descriptive title** +* **Provide a detailed description of the suggested enhancement** +* **Explain why this enhancement would be useful** +* **List some examples of how this enhancement would be used** + +### Pull Requests + +* Fill in the required template +* Follow the Go style guide +* Include comments in your code where necessary +* Update documentation if needed + +## Development Setup + +### Prerequisites + +* Go 1.21 or later +* Git + +### Building + +```bash +# Clone the repository +git clone https://github.com/y0sy4/tg-ws-proxy-go.git +cd tg-ws-proxy-go + +# Build for your platform +go build -o TgWsProxy.exe ./cmd/proxy # Windows +go build -o TgWsProxy_linux ./cmd/proxy # Linux +go build -o TgWsProxy_macos ./cmd/proxy # macOS +``` + +### Running Tests + +```bash +go test -v ./internal/... +``` + +## Code Style + +* Follow [Effective Go](https://golang.org/doc/effective_go) +* Use `gofmt` or `goimports` to format code +* Keep functions small and focused +* Add comments for exported functions + +## Questions? + +Feel free to open an issue for any questions! diff --git a/README.md b/README.md index d7b5d4f..225c943 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,10 @@ go build -o TgWsProxy.exe ./cmd/proxy ### Запуск ```bash -# Windows +# Windows (автоматически откроет настройку прокси в Telegram) start run.bat -# Windows с авто-настройкой Telegram -TgWsProxy.exe --auto-config - -# Linux/macOS +# Linux/macOS (автоматически откроет настройку прокси в Telegram) ./TgWsProxy # С опциями diff --git a/cmd/proxy/main.go b/cmd/proxy/main.go index 278885c..616a153 100644 --- a/cmd/proxy/main.go +++ b/cmd/proxy/main.go @@ -31,7 +31,6 @@ func main() { bufKB := flag.Int("buf-kb", 256, "Socket buffer size in KB") poolSize := flag.Int("pool-size", 4, "WS pool size per DC") auth := flag.String("auth", "", "SOCKS5 authentication (username:password)") - autoConfig := flag.Bool("auto-config", false, "Auto-configure Telegram Desktop on startup") showVersion := flag.Bool("version", false, "Show version") flag.Parse() @@ -89,25 +88,24 @@ func main() { log.Fatalf("Failed to create server: %v", err) } - // Auto-configure Telegram Desktop - if *autoConfig { - log.Println("Attempting to auto-configure Telegram Desktop...") - username, password := "", "" - if cfg.Auth != "" { - parts := strings.SplitN(cfg.Auth, ":", 2) - if len(parts) == 2 { - username, password = parts[0], parts[1] - } - } - if telegram.ConfigureProxy(cfg.Host, cfg.Port, username, password) { - log.Println("✓ Telegram Desktop proxy configuration opened") - } else { - log.Println("✗ Failed to open Telegram Desktop. Please configure manually.") - log.Println(" Open in browser: tg://socks?server=127.0.0.1&port=1080") + // Auto-configure Telegram Desktop (always attempt on first run) + log.Println("Attempting to configure Telegram Desktop...") + username, password := "", "" + if cfg.Auth != "" { + parts := strings.SplitN(cfg.Auth, ":", 2) + if len(parts) == 2 { + username, password = parts[0], parts[1] } } + if telegram.ConfigureProxy(cfg.Host, cfg.Port, username, password) { + log.Println("✓ Telegram Desktop proxy configuration opened") + } else { + log.Println("✗ Failed to auto-configure Telegram.") + log.Println(" Manual setup: Settings → Advanced → Connection Type → Proxy") + log.Println(" Or open: tg://socks?server=127.0.0.1&port=1080") + } - // Check for updates (non-blocking) + // Check for updates and auto-download (non-blocking) go func() { hasUpdate, latest, url, err := version.CheckUpdate() if err != nil { @@ -115,7 +113,18 @@ func main() { } if hasUpdate { log.Printf("⚡ NEW VERSION AVAILABLE: v%s (current: v%s)", latest, version.CurrentVersion) - log.Printf(" Download: %s", url) + log.Printf(" Downloading update...") + + // Try to download update + downloadedPath, err := version.DownloadUpdate(latest) + if err != nil { + log.Printf(" Download failed: %v", err) + log.Printf(" Manual download: %s", url) + return + } + + log.Printf(" ✓ Downloaded to: %s", downloadedPath) + log.Printf(" Restart the proxy to apply update") } }() diff --git a/internal/version/version.go b/internal/version/version.go index 67a9d63..3abd33f 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -6,6 +6,9 @@ import ( "fmt" "io" "net/http" + "os" + "path/filepath" + "runtime" "strings" "time" ) @@ -16,10 +19,16 @@ const ( ) type Release struct { - TagName string `json:"tag_name"` - Name string `json:"name"` - Body string `json:"body"` - HTMLURL string `json:"html_url"` + TagName string `json:"tag_name"` + Name string `json:"name"` + Body string `json:"body"` + HTMLURL string `json:"html_url"` + Assets []Asset `json:"assets"` +} + +type Asset struct { + Name string `json:"name"` + BrowserDownloadURL string `json:"browser_download_url"` } // CheckUpdate checks for new version on GitHub. @@ -53,6 +62,85 @@ func CheckUpdate() (bool, string, string, error) { return false, current, "", nil } +// DownloadUpdate downloads the latest version for current platform. +// Returns path to downloaded file or error. +func DownloadUpdate(latestVersion string) (string, error) { + client := &http.Client{Timeout: 30 * time.Second} + + resp, err := client.Get(RepoURL) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + var release Release + if err := json.Unmarshal(body, &release); err != nil { + return "", err + } + + // Find asset for current platform + assetName := getAssetName() + for _, asset := range release.Assets { + if asset.Name == assetName { + return downloadAsset(client, asset.BrowserDownloadURL, assetName) + } + } + + return "", fmt.Errorf("no asset found for %s", runtime.GOOS) +} + +func getAssetName() string { + switch runtime.GOOS { + case "windows": + return "TgWsProxy_windows_amd64.exe" + case "linux": + return "TgWsProxy_linux_amd64" + case "darwin": + if runtime.GOARCH == "arm64" { + return "TgWsProxy_darwin_arm64" + } + return "TgWsProxy_darwin_amd64" + default: + return "" + } +} + +func downloadAsset(client *http.Client, url, filename string) (string, error) { + resp, err := client.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + // Get executable directory + exe, err := os.Executable() + if err != nil { + return "", err + } + exeDir := filepath.Dir(exe) + + // Download to temp file first + tempPath := filepath.Join(exeDir, filename+".new") + out, err := os.Create(tempPath) + if err != nil { + return "", err + } + defer out.Close() + + _, err = io.Copy(out, resp.Body) + if err != nil { + os.Remove(tempPath) + return "", err + } + + return tempPath, nil +} + // compareVersions compares two semantic versions. // Returns: 1 if v1 > v2, -1 if v1 < v2, 0 if equal. func compareVersions(v1, v2 string) int {