mirror of
https://git.phreedom.club/localhost_frssoft/compy.git
synced 2024-11-27 10:31:31 +00:00
parent
8ac256351f
commit
69b89413bd
|
@ -76,6 +76,12 @@ Probably the best option is to run it with both TLS and MitM support, combining
|
||||||
compy -cert cert.crt -key cert.key -ca ca.crt -cakey ca.key
|
compy -cert cert.crt -key cert.key -ca ca.crt -cakey ca.key
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can limit access to your proxy via HTTP BASIC authentication:
|
||||||
|
|
||||||
|
```
|
||||||
|
compy -cert cert.crt -key cert.key -user myuser -pass mypass
|
||||||
|
```
|
||||||
|
|
||||||
You can also specify the listen port (defaults to 9999):
|
You can also specify the listen port (defaults to 9999):
|
||||||
```
|
```
|
||||||
compy -host :9999
|
compy -host :9999
|
||||||
|
|
9
compy.go
9
compy.go
|
@ -17,6 +17,8 @@ var (
|
||||||
key = flag.String("key", "", "proxy cert key path")
|
key = flag.String("key", "", "proxy cert key path")
|
||||||
ca = flag.String("ca", "", "CA path")
|
ca = flag.String("ca", "", "CA path")
|
||||||
caKey = flag.String("cakey", "", "CA key path")
|
caKey = flag.String("cakey", "", "CA key path")
|
||||||
|
user = flag.String("user", "", "proxy user name")
|
||||||
|
pass = flag.String("pass", "", "proxy password")
|
||||||
|
|
||||||
brotli = flag.Int("brotli", -1, "Brotli compression level (0-11, default 6)")
|
brotli = flag.Int("brotli", -1, "Brotli compression level (0-11, default 6)")
|
||||||
jpeg = flag.Int("jpeg", 50, "jpeg quality (1-100, 0 to disable)")
|
jpeg = flag.Int("jpeg", 50, "jpeg quality (1-100, 0 to disable)")
|
||||||
|
@ -45,6 +47,13 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: require cert and key?
|
||||||
|
if (*user == "") != (*pass == "") {
|
||||||
|
log.Fatalln("must specify both user and pass")
|
||||||
|
} else {
|
||||||
|
p.SetAuthentication(*user, *pass)
|
||||||
|
}
|
||||||
|
|
||||||
if *jpeg != 0 {
|
if *jpeg != 0 {
|
||||||
p.AddTranscoder("image/jpeg", tc.NewJpeg(*jpeg))
|
p.AddTranscoder("image/jpeg", tc.NewJpeg(*jpeg))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
gzipp "compress/gzip"
|
gzipp "compress/gzip"
|
||||||
|
"encoding/base64"
|
||||||
gifp "image/gif"
|
gifp "image/gif"
|
||||||
jpegp "image/jpeg"
|
jpegp "image/jpeg"
|
||||||
pngp "image/png"
|
pngp "image/png"
|
||||||
|
@ -183,3 +184,34 @@ func (s *CompyTest) TestPngToWebP(c *C) {
|
||||||
_, err = webp.Decode(resp.Body)
|
_, err = webp.Decode(resp.Body)
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *CompyTest) TestAuthentication(c *C) {
|
||||||
|
s.proxy.SetAuthentication("user", "pass")
|
||||||
|
defer s.proxy.SetAuthentication("", "")
|
||||||
|
|
||||||
|
// no password
|
||||||
|
resp, err := s.client.Get(s.server.URL + "/status/200")
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
c.Assert(resp.StatusCode, Equals, 407)
|
||||||
|
|
||||||
|
// incorrect password
|
||||||
|
req, err := http.NewRequest("GET", s.server.URL+"/status/200", nil)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
req.Header.Add("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("wrong:bad")))
|
||||||
|
|
||||||
|
resp, err = s.client.Do(req)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
c.Assert(resp.StatusCode, Equals, 407)
|
||||||
|
|
||||||
|
// correct password
|
||||||
|
req, err = http.NewRequest("GET", s.server.URL+"/status/200", nil)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
req.Header.Add("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("user:pass")))
|
||||||
|
|
||||||
|
resp, err = s.client.Do(req)
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
c.Assert(resp.StatusCode, Equals, 200)
|
||||||
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,6 +15,8 @@ type Proxy struct {
|
||||||
ml *mitmListener
|
ml *mitmListener
|
||||||
ReadCount uint64
|
ReadCount uint64
|
||||||
WriteCount uint64
|
WriteCount uint64
|
||||||
|
user string
|
||||||
|
pass string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Transcoder interface {
|
type Transcoder interface {
|
||||||
|
@ -37,6 +41,11 @@ func (p *Proxy) EnableMitm(ca, key string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Proxy) SetAuthentication(user, pass string) {
|
||||||
|
p.user = user
|
||||||
|
p.pass = pass
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Proxy) AddTranscoder(contentType string, transcoder Transcoder) {
|
func (p *Proxy) AddTranscoder(contentType string, transcoder Transcoder) {
|
||||||
p.transcoders[contentType] = transcoder
|
p.transcoders[contentType] = transcoder
|
||||||
}
|
}
|
||||||
|
@ -56,10 +65,36 @@ func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Proxy) checkHttpBasicAuth(auth string) bool {
|
||||||
|
prefix := "Basic "
|
||||||
|
if !strings.HasPrefix(auth, prefix) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
decoded, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
values := strings.SplitN(string(decoded), ":", 2)
|
||||||
|
if len(values) != 2 || values[0] != p.user || values[1] != p.pass {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Proxy) handle(w http.ResponseWriter, r *http.Request) error {
|
func (p *Proxy) handle(w http.ResponseWriter, r *http.Request) error {
|
||||||
if r.Method == "CONNECT" {
|
if r.Method == "CONNECT" {
|
||||||
return p.handleConnect(w, r)
|
return p.handleConnect(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: only HTTPS?
|
||||||
|
if p.user != "" {
|
||||||
|
if !p.checkHttpBasicAuth(r.Header.Get("Proxy-Authorization")) {
|
||||||
|
w.Header().Set("WWW-Authenticate", "Basic realm=\"Compy\"")
|
||||||
|
w.WriteHeader(http.StatusProxyAuthRequired)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := forward(r)
|
resp, err := forward(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
|
Loading…
Reference in a new issue