This is a fork of:
https://github.com/roglew/puppy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
4.1 KiB
170 lines
4.1 KiB
package puppy |
|
|
|
import ( |
|
"encoding/pem" |
|
"html/template" |
|
"net/http" |
|
"strings" |
|
) |
|
|
|
|
|
func responseHeaders(w http.ResponseWriter) { |
|
w.Header().Set("Connection", "close") |
|
w.Header().Set("Cache-control", "no-cache") |
|
w.Header().Set("Pragma", "no-cache") |
|
w.Header().Set("Cache-control", "no-store") |
|
w.Header().Set("X-Frame-Options", "DENY") |
|
} |
|
|
|
// Generate a proxy-compatible web handler that allows users to download certificates and view responses stored in the storage used by the proxyin the browser |
|
func CreateWebUIHandler() ProxyWebUIHandler { |
|
var masterSrc string = ` |
|
<html> |
|
<head> |
|
<title>{{block "title" .}}Puppy Proxy{{end}}</title> |
|
{{block "head" .}}{{end}} |
|
</head> |
|
<body> |
|
{{block "body" .}}{{end}} |
|
</body> |
|
</html> |
|
` |
|
var masterTpl *template.Template |
|
|
|
var homeSrc string = ` |
|
{{define "title"}}Puppy Home{{end}} |
|
{{define "body"}} |
|
<p>Welcome to Puppy<p> |
|
<ul> |
|
<li><a href="/certs">Download CA certificate</a></li> |
|
</ul> |
|
{{end}} |
|
` |
|
var homeTpl *template.Template |
|
|
|
var certsSrc string = ` |
|
{{define "title"}}CA Certificate{{end}} |
|
{{define "body"}} |
|
<p>Downlad this CA cert and add it to your browser to intercept HTTPS messages<p> |
|
<p><a href="/certs/download">Download</p> |
|
{{end}} |
|
` |
|
var certsTpl *template.Template |
|
|
|
var rspviewSrc string = ` |
|
{{define "title"}}Response Viewer{{end}} |
|
{{define "head"}} |
|
<script> |
|
function ViewResponse() { |
|
rspid = document.getElementById("rspid").value |
|
window.location.href = "/rsp/" + rspid |
|
} |
|
</script> |
|
{{end}} |
|
{{define "body"}} |
|
<p>Enter a response ID below to view it in the browser<p> |
|
<input type="text" id="rspid"></input><input type="button" onclick="ViewResponse()" value="Go!"></input> |
|
{{end}} |
|
` |
|
var rspviewTpl *template.Template |
|
|
|
var err error |
|
masterTpl, err = template.New("master").Parse(masterSrc) |
|
if err != nil { |
|
panic(err) |
|
} |
|
|
|
homeTpl, err = template.Must(masterTpl.Clone()).Parse(homeSrc) |
|
if err != nil { |
|
panic(err) |
|
} |
|
|
|
certsTpl, err = template.Must(masterTpl.Clone()).Parse(certsSrc) |
|
if err != nil { |
|
panic(err) |
|
} |
|
|
|
rspviewTpl, err = template.Must(masterTpl.Clone()).Parse(rspviewSrc) |
|
if err != nil { |
|
panic(err) |
|
} |
|
|
|
var WebUIRootHandler = func(w http.ResponseWriter, r *http.Request, iproxy *InterceptingProxy) { |
|
err := homeTpl.Execute(w, nil) |
|
if err != nil { |
|
http.Error(w, err.Error(), http.StatusInternalServerError) |
|
return |
|
} |
|
} |
|
|
|
var WebUICertsHandler = func(w http.ResponseWriter, r *http.Request, iproxy *InterceptingProxy, path []string) { |
|
if len(path) > 0 && path[0] == "download" { |
|
cert := iproxy.GetCACertificate() |
|
if cert == nil { |
|
w.Write([]byte("no active certs to download")) |
|
return |
|
} |
|
|
|
pemData := pem.EncodeToMemory( |
|
&pem.Block{ |
|
Type: "CERTIFICATE", |
|
Bytes: cert.Certificate[0], |
|
}, |
|
) |
|
w.Header().Set("Content-Type", "application/octet-stream") |
|
w.Header().Set("Content-Disposition", "attachment; filename=\"cert.pem\"") |
|
w.Write(pemData) |
|
return |
|
} |
|
err := certsTpl.Execute(w, nil) |
|
if err != nil { |
|
http.Error(w, err.Error(), http.StatusInternalServerError) |
|
return |
|
} |
|
} |
|
|
|
var viewResponseHeaders = func(w http.ResponseWriter) { |
|
w.Header().Del("Cookie") |
|
} |
|
|
|
var WebUIRspHandler = func(w http.ResponseWriter, r *http.Request, iproxy *InterceptingProxy, path []string) { |
|
if len(path) > 0 { |
|
reqid := path[0] |
|
ms := iproxy.GetProxyStorage() |
|
req, err := ms.LoadRequest(reqid) |
|
if err != nil { |
|
http.Error(w, err.Error(), http.StatusInternalServerError) |
|
return |
|
} |
|
rsp := req.ServerResponse |
|
for k, v := range rsp.Header { |
|
for _, vv := range v { |
|
w.Header().Add(k, vv) |
|
} |
|
} |
|
viewResponseHeaders(w) |
|
w.WriteHeader(rsp.StatusCode) |
|
w.Write(rsp.BodyBytes()) |
|
return |
|
} |
|
err := rspviewTpl.Execute(w, nil) |
|
if err != nil { |
|
http.Error(w, err.Error(), http.StatusInternalServerError) |
|
return |
|
} |
|
} |
|
|
|
return func(w http.ResponseWriter, r *http.Request, iproxy *InterceptingProxy) { |
|
responseHeaders(w) |
|
parts := strings.Split(r.URL.Path, "/") |
|
switch parts[1] { |
|
case "": |
|
WebUIRootHandler(w, r, iproxy) |
|
case "certs": |
|
WebUICertsHandler(w, r, iproxy, parts[2:]) |
|
case "rsp": |
|
WebUIRspHandler(w, r, iproxy, parts[2:]) |
|
} |
|
} |
|
|
|
}
|
|
|