diff --git a/config.go b/config.go index 7053c12..c92bd63 100644 --- a/config.go +++ b/config.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" + "github.com/hrfee/jfa-go/easyproxy" "gopkg.in/ini.v1" ) @@ -135,6 +136,22 @@ func (app *appContext) loadConfig() error { messagesEnabled = false } + if app.proxyEnabled = app.config.Section("advanced").Key("proxy").MustBool(false); app.proxyEnabled { + app.proxyConfig = easyproxy.ProxyConfig{} + app.proxyConfig.Protocol = easyproxy.HTTP + if strings.Contains(app.config.Section("advanced").Key("proxy_protocol").MustString("http"), "socks") { + app.proxyConfig.Protocol = easyproxy.SOCKS5 + } + app.proxyConfig.Addr = app.config.Section("advanced").Key("proxy_address").MustString("") + app.proxyConfig.User = app.config.Section("advanced").Key("proxy_user").MustString("") + app.proxyConfig.Password = app.config.Section("advanced").Key("proxy_password").MustString("") + app.proxyTransport, err = easyproxy.NewTransport(app.proxyConfig) + if err != nil { + app.err.Printf("Failed to initialize Proxy: %v\n", err) + } + app.proxyEnabled = true + } + app.MustSetValue("updates", "enabled", "true") releaseChannel := app.config.Section("updates").Key("channel").String() if app.config.Section("updates").Key("enabled").MustBool(false) { @@ -147,6 +164,9 @@ func (app *appContext) loadConfig() error { v = "git" } app.updater = newUpdater(baseURL, namespace, repo, v, commit, updater) + if app.proxyEnabled { + app.updater.SetTransport(app.proxyTransport) + } } if releaseChannel == "" { if version == "git" { diff --git a/easyproxy/easyproxy.go b/easyproxy/easyproxy.go index b9c9bba..ef6557b 100644 --- a/easyproxy/easyproxy.go +++ b/easyproxy/easyproxy.go @@ -1,10 +1,12 @@ -// Package easyproxy provides a method to quickly create a http.Transport using given proxy details (SOCKS5 or HTTP). +// Package easyproxy provides a method to quickly create a http.Transport or net.Conn using given proxy details (SOCKS5 or HTTP). package easyproxy import ( + "crypto/tls" "net/http" "net/url" + "github.com/magisterquis/connectproxy" "golang.org/x/net/proxy" ) @@ -15,28 +17,67 @@ const ( HTTP // HTTP ) +type ProxyConfig struct { + Protocol Protocol + Addr string + User string + Password string +} + // NewTransport returns a http.Transport using the given proxy details. Leave user/pass blank if not needed. -func NewTransport(p Protocol, addr, user, pass string) (*http.Transport, error) { +func NewTransport(c ProxyConfig) (*http.Transport, error) { t := &http.Transport{} - if p == HTTP { + if c.Protocol == HTTP { u := &url.URL{ Scheme: "http", - Host: addr, + Host: c.Addr, } - if user != "" && pass != "" { - u.User = url.UserPassword(user, pass) + if c.User != "" && c.Password != "" { + u.User = url.UserPassword(c.User, c.Password) } t.Proxy = http.ProxyURL(u) return t, nil } var auth *proxy.Auth = nil - if user != "" && pass != "" { - auth = &proxy.Auth{User: user, Password: pass} + if c.User != "" && c.Password != "" { + auth = &proxy.Auth{User: c.User, Password: c.Password} } - dialer, err := proxy.SOCKS5("tcp", addr, auth, proxy.Direct) + dialer, err := proxy.SOCKS5("tcp", c.Addr, auth, proxy.Direct) if err != nil { - return nil, nil + return nil, err } t.Dial = dialer.Dial return t, nil } + +// NewConn returns a tls.Conn to "addr" using the given proxy details. Leave user/pass blank if not needed. +func NewConn(c ProxyConfig, addr string, tlsConf *tls.Config) (*tls.Conn, error) { + var proxyDialer proxy.Dialer + var err error + if c.Protocol == SOCKS5 { + var auth *proxy.Auth = nil + if c.User != "" && c.Password != "" { + auth = &proxy.Auth{User: c.User, Password: c.Password} + } + proxyDialer, err = proxy.SOCKS5("tcp", c.Addr, auth, proxy.Direct) + if err != nil { + return nil, err + } + } else { + u := &url.URL{ + Scheme: "http", + Host: c.Addr, + } + if c.User != "" && c.Password != "" { + u.User = url.UserPassword(c.User, c.Password) + } + proxyDialer, err = connectproxy.New(u, proxy.Direct) + } + + dialer, err := proxyDialer.Dial("tcp", addr) + if err != nil { + return nil, err + } + conn := tls.Client(dialer, tlsConf) + return conn, nil +} diff --git a/easyproxy/go.mod b/easyproxy/go.mod index d2c531f..f88550a 100644 --- a/easyproxy/go.mod +++ b/easyproxy/go.mod @@ -3,3 +3,5 @@ module github.com/hrfee/jfa-go/easyproxy go 1.20 require golang.org/x/net v0.15.0 + +require github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b // indirect diff --git a/easyproxy/go.sum b/easyproxy/go.sum index 9746d02..a131b72 100644 --- a/easyproxy/go.sum +++ b/easyproxy/go.sum @@ -1,2 +1,4 @@ +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI= +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= diff --git a/email.go b/email.go index 0f517ca..9671ee4 100644 --- a/email.go +++ b/email.go @@ -19,6 +19,7 @@ import ( "github.com/gomarkdown/markdown" "github.com/gomarkdown/markdown/html" + "github.com/hrfee/jfa-go/easyproxy" "github.com/hrfee/mediabrowser" "github.com/itchyny/timefmt-go" "github.com/mailgun/mailgun-go/v4" @@ -87,7 +88,11 @@ func NewEmailer(app *appContext) *Emailer { if username == "" && password != "" { username = emailer.fromAddr } - err := emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, password, sslTLS, app.config.Section("smtp").Key("ssl_cert").MustString(""), app.config.Section("smtp").Key("hello_hostname").String(), app.config.Section("smtp").Key("cert_validation").MustBool(true)) + var proxyConf *easyproxy.ProxyConfig = nil + if app.proxyEnabled { + proxyConf = &app.proxyConfig + } + err := emailer.NewSMTP(app.config.Section("smtp").Key("server").String(), app.config.Section("smtp").Key("port").MustInt(465), username, password, sslTLS, app.config.Section("smtp").Key("ssl_cert").MustString(""), app.config.Section("smtp").Key("hello_hostname").String(), app.config.Section("smtp").Key("cert_validation").MustBool(true), proxyConf) if err != nil { app.err.Printf("Error while initiating SMTP mailer: %v", err) } @@ -113,7 +118,7 @@ type SMTP struct { } // NewSMTP returns an SMTP emailClient. -func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool, certPath string, helloHostname string, validateCertificate bool) (err error) { +func (emailer *Emailer) NewSMTP(server string, port int, username, password string, sslTLS bool, certPath string, helloHostname string, validateCertificate bool, proxy *easyproxy.ProxyConfig) (err error) { sender := &SMTP{} sender.Client = sMail.NewSMTPClient() if sslTLS { @@ -131,12 +136,16 @@ func (emailer *Emailer) NewSMTP(server string, port int, username, password stri sender.Client.Host = server sender.Client.Port = port sender.Client.KeepAlive = false + // x509.SystemCertPool is unavailable on windows if PLATFORM == "windows" { sender.Client.TLSConfig = &tls.Config{ InsecureSkipVerify: !validateCertificate, ServerName: server, } + if proxy != nil { + sender.Client.CustomConn, err = easyproxy.NewConn(*proxy, fmt.Sprintf("%s:%d", server, port), sender.Client.TLSConfig) + } emailer.sender = sender return } @@ -156,6 +165,9 @@ func (emailer *Emailer) NewSMTP(server string, port int, username, password stri ServerName: server, RootCAs: rootCAs, } + if proxy != nil { + sender.Client.CustomConn, err = easyproxy.NewConn(*proxy, fmt.Sprintf("%s:%d", server, port), sender.Client.TLSConfig) + } emailer.sender = sender return } diff --git a/go.mod b/go.mod index c4650b4..f2866a2 100644 --- a/go.mod +++ b/go.mod @@ -43,7 +43,7 @@ require ( github.com/swaggo/gin-swagger v1.6.0 github.com/timshannon/badgerhold/v4 v4.0.2 github.com/writeas/go-strip-markdown v2.0.1+incompatible - github.com/xhit/go-simple-mail/v2 v2.13.0 + github.com/xhit/go-simple-mail/v2 v2.16.0 gopkg.in/ini.v1 v1.67.0 maunium.net/go/mautrix v0.15.3 ) @@ -93,6 +93,7 @@ require ( github.com/klauspost/compress v1.16.6 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect + github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect diff --git a/go.sum b/go.sum index 85f8f14..07de685 100644 --- a/go.sum +++ b/go.sum @@ -264,6 +264,8 @@ github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaK github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b h1:xZ59n7Frzh8CwyfAapUZLSg+gXH5m63YEaFCMpDHhpI= +github.com/magisterquis/connectproxy v0.0.0-20200725203833-3582e84f0c9b/go.mod h1:uDd4sYVYsqcxAB8j+Q7uhL6IJCs/r1kxib1HV4bgOMg= github.com/mailgun/mailgun-go/v4 v4.9.1 h1:D/jhJXYod4RqRsNOOSrjrtAcMEnz8mPYJmeA5cueHKY= github.com/mailgun/mailgun-go/v4 v4.9.1/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -394,6 +396,8 @@ github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6Fk github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE= github.com/xhit/go-simple-mail/v2 v2.13.0 h1:OANWU9jHZrVfBkNkvLf8Ww0fexwpQVF/v/5f96fFTLI= github.com/xhit/go-simple-mail/v2 v2.13.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98= +github.com/xhit/go-simple-mail/v2 v2.16.0 h1:ouGy/Ww4kuaqu2E2UrDw7SvLaziWTB60ICLkIkNVccA= +github.com/xhit/go-simple-mail/v2 v2.16.0/go.mod h1:b7P5ygho6SYE+VIqpxA6QkYfv4teeyG4MKqB3utRu98= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= diff --git a/main.go b/main.go index 45ed009..8156edf 100644 --- a/main.go +++ b/main.go @@ -114,6 +114,9 @@ type appContext struct { newUpdate bool // Whether whatever's in update is new. tag Tag update Update + proxyEnabled bool + proxyTransport *http.Transport + proxyConfig easyproxy.ProxyConfig internalPWRs map[string]InternalPWR ConfirmationKeys map[string]map[string]newUserDTO // Map of invite code to jwt to request confirmationKeysLock sync.Mutex @@ -392,20 +395,8 @@ func start(asDaemon, firstCall bool) { app.jf.Verbose = true } - if app.config.Section("advanced").Key("proxy").MustBool(false) { - // FIXME: Use Proxy - protocol := easyproxy.HTTP - if strings.Contains(app.config.Section("advanced").Key("proxy_protocol").MustString("http"), "socks") { - protocol = easyproxy.SOCKS5 - } - addr := app.config.Section("advanced").Key("proxy_address").MustString("") - user := app.config.Section("advanced").Key("proxy_user").MustString("") - password := app.config.Section("advanced").Key("proxy_password").MustString("") - transport, err := easyproxy.NewTransport(protocol, addr, user, password) - if err != nil { - app.err.Printf("Failed to initialize Proxy: %v\n", err) - } - app.jf.SetTransport(transport) + if app.proxyEnabled { + app.jf.SetTransport(app.proxyTransport) } var status int diff --git a/updater.go b/updater.go index c6c8c62..1e0e78a 100644 --- a/updater.go +++ b/updater.go @@ -185,6 +185,11 @@ type BuildDTO struct { Tags map[string]Tag } +// SetTransport sets the http.Transport to use for requests. Can be used to set a proxy. +func (ud *Updater) SetTransport(t *http.Transport) { + ud.httpClient.Transport = t +} + func (ud *Updater) GetTag() (Tag, int, error) { if ud.buildType == off { return Tag{}, -1, nil