mirror of
https://git.phreedom.club/localhost_frssoft/compy.git
synced 2024-11-27 02:21:34 +00:00
Serve diagnostics and CA certificate
Fixes #21. Reference: https://mtersch.wordpress.com/2015/03/17/certificate-import-in-firefox-on-android/
This commit is contained in:
parent
703cb4adaf
commit
f69a0b7e0e
2
compy.go
2
compy.go
|
@ -31,7 +31,7 @@ var (
|
|||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
p := proxy.New()
|
||||
p := proxy.New(*host, cert)
|
||||
|
||||
if (*ca == "") != (*caKey == "") {
|
||||
log.Fatalln("must specify both CA certificate and key")
|
||||
|
|
|
@ -37,7 +37,7 @@ var _ = Suite(&CompyTest{})
|
|||
func (s *CompyTest) SetUpSuite(c *C) {
|
||||
s.server = httptest.NewServer(httpbin.GetMux())
|
||||
|
||||
s.proxy = proxy.New()
|
||||
s.proxy = proxy.New("localhost"+*host, nil)
|
||||
s.proxy.AddTranscoder("image/gif", &tc.Gif{})
|
||||
s.proxy.AddTranscoder("image/jpeg", tc.NewJpeg(50))
|
||||
s.proxy.AddTranscoder("image/png", &tc.Png{})
|
||||
|
@ -243,3 +243,20 @@ func (s *CompyTest) TestAuthentication(c *C) {
|
|||
defer resp.Body.Close()
|
||||
c.Assert(resp.StatusCode, Equals, 200)
|
||||
}
|
||||
|
||||
func (s *CompyTest) TestAdmin(c *C) {
|
||||
resp, err := s.client.Get("http://localhost" + *host)
|
||||
c.Assert(err, IsNil)
|
||||
defer resp.Body.Close()
|
||||
c.Assert(resp.StatusCode, Equals, 200)
|
||||
|
||||
resp, err = s.client.Get("http://localhost" + *host + "/cacert")
|
||||
c.Assert(err, IsNil)
|
||||
defer resp.Body.Close()
|
||||
c.Assert(resp.StatusCode, Equals, 404)
|
||||
|
||||
resp, err = s.client.Get("http://localhost" + *host + "/fake")
|
||||
c.Assert(err, IsNil)
|
||||
defer resp.Body.Close()
|
||||
c.Assert(resp.StatusCode, Equals, 501)
|
||||
}
|
||||
|
|
|
@ -8,12 +8,14 @@ import (
|
|||
type mitmListener struct {
|
||||
c chan net.Conn
|
||||
cf *certFaker
|
||||
config *tls.Config
|
||||
}
|
||||
|
||||
func newMitmListener(cf *certFaker) *mitmListener {
|
||||
func newMitmListener(cf *certFaker, config *tls.Config) *mitmListener {
|
||||
return &mitmListener{
|
||||
c: make(chan net.Conn),
|
||||
cf: cf,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,7 +32,7 @@ func (l *mitmListener) Addr() net.Addr {
|
|||
}
|
||||
|
||||
func (l *mitmListener) Serve(conn net.Conn, host string) (net.Conn, error) {
|
||||
sconn, err := tls.Dial("tcp", host, nil)
|
||||
sconn, err := tls.Dial("tcp", host, l.config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
@ -17,16 +23,20 @@ type Proxy struct {
|
|||
WriteCount uint64
|
||||
user string
|
||||
pass string
|
||||
host string
|
||||
cert *string
|
||||
}
|
||||
|
||||
type Transcoder interface {
|
||||
Transcode(*ResponseWriter, *ResponseReader, http.Header) error
|
||||
}
|
||||
|
||||
func New() *Proxy {
|
||||
func New(host string, cert *string) *Proxy {
|
||||
p := &Proxy{
|
||||
transcoders: make(map[string]Transcoder),
|
||||
ml: nil,
|
||||
host: host,
|
||||
cert: cert,
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
@ -36,7 +46,25 @@ func (p *Proxy) EnableMitm(ca, key string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.ml = newMitmListener(cf)
|
||||
|
||||
var config *tls.Config
|
||||
if p.cert != nil {
|
||||
roots, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pem, err := ioutil.ReadFile(*p.cert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ok := roots.AppendCertsFromPEM([]byte(pem))
|
||||
if !ok {
|
||||
return errors.New("failed to parse root certificate")
|
||||
}
|
||||
config = &tls.Config{RootCAs: roots}
|
||||
}
|
||||
|
||||
p.ml = newMitmListener(cf, config)
|
||||
go http.Serve(p.ml, p)
|
||||
return nil
|
||||
}
|
||||
|
@ -95,6 +123,14 @@ func (p *Proxy) handle(w http.ResponseWriter, r *http.Request) error {
|
|||
return p.handleConnect(w, r)
|
||||
}
|
||||
|
||||
host := r.URL.Host
|
||||
if host == "" {
|
||||
host = r.Host
|
||||
}
|
||||
if hostname, err := os.Hostname(); host == p.host || (err == nil && host == hostname+p.host) {
|
||||
return p.handleLocalRequest(w, r)
|
||||
}
|
||||
|
||||
resp, err := forward(r)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
@ -112,6 +148,39 @@ func (p *Proxy) handle(w http.ResponseWriter, r *http.Request) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (p *Proxy) handleLocalRequest(w http.ResponseWriter, r *http.Request) error {
|
||||
if r.Method == "GET" && (r.URL.Path == "" || r.URL.Path == "/") {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
read := atomic.LoadUint64(&p.ReadCount)
|
||||
written := atomic.LoadUint64(&p.WriteCount)
|
||||
io.WriteString(w, fmt.Sprintf(`<html>
|
||||
<head>
|
||||
<title>compy</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>compy</h1>
|
||||
<ul>
|
||||
<li>total transcoded: %d -> %d (%3.1f%%)</li>
|
||||
<li><a href="/cacert">CA cert</a></li>
|
||||
<li><a href="https://github.com/barnacs/compy">GitHub</a></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>`, read, written, float64(written)/float64(read)*100))
|
||||
return nil
|
||||
} else if r.Method == "GET" && r.URL.Path == "/cacert" {
|
||||
if p.cert == nil {
|
||||
http.NotFound(w, r)
|
||||
return nil
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/x-x509-ca-cert")
|
||||
http.ServeFile(w, r, *p.cert)
|
||||
return nil
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotImplemented)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func forward(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Scheme == "" {
|
||||
if r.TLS != nil && r.TLS.ServerName == r.Host {
|
||||
|
|
Loading…
Reference in a new issue