mirror of
https://github.com/boringproxy/boringproxy.git
synced 2025-02-25 18:55:29 -06:00
Implement password-protected tunnels
This commit is contained in:
parent
85a5004cc7
commit
fd0451fa3b
18
api.go
18
api.go
@ -79,6 +79,22 @@ func (a *Api) CreateTunnel(tokenData TokenData, params url.Values) (*Tunnel, err
|
||||
|
||||
allowExternalTcp := params.Get("allow-external-tcp") == "on"
|
||||
|
||||
passwordProtect := params.Get("password-protect") == "on"
|
||||
|
||||
var username string
|
||||
var password string
|
||||
if passwordProtect {
|
||||
username = params.Get("username")
|
||||
if username == "" {
|
||||
return nil, errors.New("Username required")
|
||||
}
|
||||
|
||||
password = params.Get("password")
|
||||
if password == "" {
|
||||
return nil, errors.New("Password required")
|
||||
}
|
||||
}
|
||||
|
||||
request := Tunnel{
|
||||
Domain: domain,
|
||||
Owner: tokenData.Owner,
|
||||
@ -86,6 +102,8 @@ func (a *Api) CreateTunnel(tokenData TokenData, params url.Values) (*Tunnel, err
|
||||
ClientPort: clientPort,
|
||||
ClientAddress: clientAddr,
|
||||
AllowExternalTcp: allowExternalTcp,
|
||||
AuthUsername: username,
|
||||
AuthPassword: password,
|
||||
}
|
||||
|
||||
tunnel, err := a.tunMan.RequestCreateTunnel(request)
|
||||
|
@ -26,6 +26,7 @@ type SmtpConfig struct {
|
||||
}
|
||||
|
||||
type BoringProxy struct {
|
||||
db *Database
|
||||
tunMan *TunnelManager
|
||||
httpClient *http.Client
|
||||
}
|
||||
@ -83,7 +84,7 @@ func Listen() {
|
||||
|
||||
httpClient := &http.Client{}
|
||||
|
||||
p := &BoringProxy{tunMan, httpClient}
|
||||
p := &BoringProxy{db, tunMan, httpClient}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
GetCertificate: certConfig.GetCertificate,
|
||||
@ -117,17 +118,34 @@ func Listen() {
|
||||
|
||||
func (p *BoringProxy) proxyRequest(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
port, err := p.tunMan.GetPort(r.Host)
|
||||
if err != nil {
|
||||
tunnel, exists := p.db.GetTunnel(r.Host)
|
||||
if !exists {
|
||||
errMessage := fmt.Sprintf("No tunnel attached to %s", r.Host)
|
||||
w.WriteHeader(500)
|
||||
io.WriteString(w, errMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if tunnel.AuthUsername != "" || tunnel.AuthPassword != "" {
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok {
|
||||
w.Header()["WWW-Authenticate"] = []string{"Basic"}
|
||||
w.WriteHeader(401)
|
||||
return
|
||||
}
|
||||
|
||||
if username != tunnel.AuthUsername || password != tunnel.AuthPassword {
|
||||
w.Header()["WWW-Authenticate"] = []string{"Basic"}
|
||||
w.WriteHeader(401)
|
||||
// TODO: should probably use a better form of rate limiting
|
||||
time.Sleep(2 * time.Second)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
downstreamReqHeaders := r.Header.Clone()
|
||||
|
||||
upstreamAddr := fmt.Sprintf("localhost:%d", port)
|
||||
upstreamAddr := fmt.Sprintf("localhost:%d", tunnel.TunnelPort)
|
||||
upstreamUrl := fmt.Sprintf("http://%s%s", upstreamAddr, r.URL.RequestURI())
|
||||
|
||||
upstreamReq, err := http.NewRequest(r.Method, upstreamUrl, r.Body)
|
||||
|
@ -36,6 +36,8 @@ type Tunnel struct {
|
||||
ClientAddress string `json:"client_address"`
|
||||
ClientPort int `json:"client_port"`
|
||||
AllowExternalTcp bool `json:"allow_external_tcp"`
|
||||
AuthUsername string `json:"auth_username"`
|
||||
AuthPassword string `json:"auth_password"`
|
||||
CssId string `json:"css_id"`
|
||||
}
|
||||
|
||||
|
@ -82,24 +82,16 @@ func (m *TunnelManager) RequestCreateTunnel(tunReq Tunnel) (Tunnel, error) {
|
||||
return Tunnel{}, err
|
||||
}
|
||||
|
||||
tunnel := Tunnel{
|
||||
Owner: tunReq.Owner,
|
||||
Domain: tunReq.Domain,
|
||||
ServerAddress: m.config.WebUiDomain,
|
||||
ServerPort: 22,
|
||||
ServerPublicKey: "",
|
||||
Username: m.user.Username,
|
||||
TunnelPort: port,
|
||||
TunnelPrivateKey: privKey,
|
||||
ClientName: tunReq.ClientName,
|
||||
ClientPort: tunReq.ClientPort,
|
||||
ClientAddress: tunReq.ClientAddress,
|
||||
AllowExternalTcp: tunReq.AllowExternalTcp,
|
||||
}
|
||||
tunReq.ServerAddress = m.config.WebUiDomain
|
||||
tunReq.ServerPort = 22
|
||||
tunReq.ServerPublicKey = ""
|
||||
tunReq.Username = m.user.Username
|
||||
tunReq.TunnelPort = port
|
||||
tunReq.TunnelPrivateKey = privKey
|
||||
|
||||
m.db.SetTunnel(tunReq.Domain, tunnel)
|
||||
m.db.SetTunnel(tunReq.Domain, tunReq)
|
||||
|
||||
return tunnel, nil
|
||||
return tunReq, nil
|
||||
}
|
||||
|
||||
func (m *TunnelManager) DeleteTunnel(domain string) error {
|
||||
|
@ -76,6 +76,17 @@
|
||||
<label for="allow-external-tcp">Allow External TCP:</label>
|
||||
<input type="checkbox" id="allow-external-tcp" name="allow-external-tcp">
|
||||
</div>
|
||||
<div class='input'>
|
||||
<label for="password-protect">Password Protect:</label>
|
||||
<input type="checkbox" id="password-protect" name="password-protect">
|
||||
|
||||
<div id='login-inputs'>
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username">
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password">
|
||||
</div>
|
||||
</div>
|
||||
<button class='button' type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -164,6 +164,14 @@ main {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#login-inputs {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#password-protect:checked ~ #login-inputs {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.token-adder {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
|
Loading…
Reference in New Issue
Block a user