mirror of
https://git.phreedom.club/localhost_frssoft/compy.git
synced 2024-11-23 08:31:29 +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
|
||||
```
|
||||
|
||||
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):
|
||||
```
|
||||
compy -host :9999
|
||||
|
|
9
compy.go
9
compy.go
|
@ -17,6 +17,8 @@ var (
|
|||
key = flag.String("key", "", "proxy cert key path")
|
||||
ca = flag.String("ca", "", "CA 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)")
|
||||
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 {
|
||||
p.AddTranscoder("image/jpeg", tc.NewJpeg(*jpeg))
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"bytes"
|
||||
gzipp "compress/gzip"
|
||||
"encoding/base64"
|
||||
gifp "image/gif"
|
||||
jpegp "image/jpeg"
|
||||
pngp "image/png"
|
||||
|
@ -183,3 +184,34 @@ func (s *CompyTest) TestPngToWebP(c *C) {
|
|||
_, err = webp.Decode(resp.Body)
|
||||
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
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
|
@ -13,6 +15,8 @@ type Proxy struct {
|
|||
ml *mitmListener
|
||||
ReadCount uint64
|
||||
WriteCount uint64
|
||||
user string
|
||||
pass string
|
||||
}
|
||||
|
||||
type Transcoder interface {
|
||||
|
@ -37,6 +41,11 @@ func (p *Proxy) EnableMitm(ca, key string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Proxy) SetAuthentication(user, pass string) {
|
||||
p.user = user
|
||||
p.pass = pass
|
||||
}
|
||||
|
||||
func (p *Proxy) AddTranscoder(contentType string, transcoder 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 {
|
||||
if r.Method == "CONNECT" {
|
||||
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)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
|
Loading…
Reference in a new issue