Run go fmt

This commit is contained in:
Anders Pitman 2020-10-02 17:09:14 -06:00
parent be91ff62ef
commit c285f0990f
7 changed files with 284 additions and 292 deletions

114
api.go
View File

@ -1,59 +1,57 @@
package main
import (
//"fmt"
//"strings"
"net/http"
"io"
"encoding/json"
//"fmt"
//"strings"
"encoding/json"
"io"
"net/http"
)
type Api struct {
config *BoringProxyConfig
auth *Auth
tunMan *TunnelManager
mux *http.ServeMux
config *BoringProxyConfig
auth *Auth
tunMan *TunnelManager
mux *http.ServeMux
}
type CreateTunnelResponse struct {
ServerAddress string `json:"server_address"`
ServerPort int `json:"server_port"`
ServerPublicKey string `json:"server_public_key"`
TunnelPort int `json:"tunnel_port"`
TunnelPrivateKey string `json:"tunnel_private_key"`
ServerAddress string `json:"server_address"`
ServerPort int `json:"server_port"`
ServerPublicKey string `json:"server_public_key"`
TunnelPort int `json:"tunnel_port"`
TunnelPrivateKey string `json:"tunnel_private_key"`
}
func NewApi(config *BoringProxyConfig, auth *Auth, tunMan *TunnelManager) *Api {
api := &Api{config, auth, tunMan, nil}
api := &Api{config, auth, tunMan, nil}
mux := http.NewServeMux()
mux := http.NewServeMux()
mux.Handle("/tunnels", http.StripPrefix("/tunnels", http.HandlerFunc(api.handleTunnels)))
mux.Handle("/tunnels", http.StripPrefix("/tunnels", http.HandlerFunc(api.handleTunnels)))
api.mux = mux
api.mux = mux
return api
return api
}
func (a *Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
a.mux.ServeHTTP(w, r)
a.mux.ServeHTTP(w, r)
}
func (a *Api) handleTunnels(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST":
a.validateSession(http.HandlerFunc(a.handleCreateTunnel)).ServeHTTP(w, r)
default:
switch r.Method {
case "POST":
a.validateSession(http.HandlerFunc(a.handleCreateTunnel)).ServeHTTP(w, r)
default:
w.WriteHeader(405)
w.Write([]byte("Invalid method for /tunnels"))
}
}
}
func (a *Api) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
query := r.URL.Query()
if len(query["domain"]) != 1 {
w.WriteHeader(400)
@ -62,47 +60,47 @@ func (a *Api) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
}
domain := query["domain"][0]
port, privKey, err := a.tunMan.CreateTunnel(domain)
if err != nil {
port, privKey, err := a.tunMan.CreateTunnel(domain)
if err != nil {
w.WriteHeader(400)
io.WriteString(w, err.Error())
io.WriteString(w, err.Error())
return
}
}
response := &CreateTunnelResponse{
ServerAddress: a.config.AdminDomain,
ServerPort: 22,
ServerPublicKey: "",
TunnelPort: port,
TunnelPrivateKey: privKey,
}
response := &CreateTunnelResponse{
ServerAddress: a.config.AdminDomain,
ServerPort: 22,
ServerPublicKey: "",
TunnelPort: port,
TunnelPrivateKey: privKey,
}
responseJson, err := json.MarshalIndent(response, "", " ")
if err != nil {
responseJson, err := json.MarshalIndent(response, "", " ")
if err != nil {
w.WriteHeader(500)
io.WriteString(w, "Error encoding response")
io.WriteString(w, "Error encoding response")
return
}
}
w.Write(responseJson)
w.Write(responseJson)
}
func (a *Api) validateSession(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token, err := extractToken("access_token", r)
if err != nil {
w.WriteHeader(401)
w.Write([]byte("No token provided"))
return
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token, err := extractToken("access_token", r)
if err != nil {
w.WriteHeader(401)
w.Write([]byte("No token provided"))
return
}
if !a.auth.Authorized(token) {
w.WriteHeader(403)
w.Write([]byte("Not authorized"))
return
}
if !a.auth.Authorized(token) {
w.WriteHeader(403)
w.Write([]byte("Not authorized"))
return
}
h.ServeHTTP(w, r)
})
h.ServeHTTP(w, r)
})
}

16
auth.go
View File

@ -20,7 +20,7 @@ type Auth struct {
}
type LoginRequest struct {
Email string
Email string
}
type Session struct {
@ -109,16 +109,16 @@ func (a *Auth) Verify(key string) (string, error) {
delete(a.pendingRequests, key)
token, err := genRandomKey()
if err != nil {
return "", errors.New("Error generating key")
}
token, err := genRandomKey()
if err != nil {
return "", errors.New("Error generating key")
}
a.sessions[token] = &Session{Id: request.Email}
a.sessions[token] = &Session{Id: request.Email}
saveJson(a.sessions, "sessions.json")
saveJson(a.sessions, "sessions.json")
return token, nil
return token, nil
}
const chars string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

View File

@ -4,16 +4,16 @@ import (
"crypto/tls"
"encoding/json"
"fmt"
"github.com/GeertJohan/go.rice"
"github.com/caddyserver/certmagic"
"html/template"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"html/template"
"strconv"
"sync"
"github.com/caddyserver/certmagic"
"github.com/GeertJohan/go.rice"
)
type BoringProxyConfig struct {
@ -70,10 +70,10 @@ func NewBoringProxy() *BoringProxy {
p := &BoringProxy{config, auth, tunMan, adminListener, certConfig}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
p.handleAdminRequest(w, r)
})
p.handleAdminRequest(w, r)
})
api := NewApi(config, auth, tunMan)
api := NewApi(config, auth, tunMan)
http.Handle("/api/", http.StripPrefix("/api", api))
go http.Serve(adminListener, nil)
@ -106,26 +106,26 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
case "/login":
p.handleLogin(w, r)
case "/":
box, err := rice.FindBox("webui")
if err != nil {
box, err := rice.FindBox("webui")
if err != nil {
w.WriteHeader(500)
io.WriteString(w, "Error opening webui")
io.WriteString(w, "Error opening webui")
return
}
}
token, err := extractToken("access_token", r)
if err != nil {
loginTemplate, err := box.String("login.tmpl")
if err != nil {
log.Println(err)
w.WriteHeader(500)
io.WriteString(w, "Error reading login.tmpl")
return
}
loginTemplate, err := box.String("login.tmpl")
if err != nil {
log.Println(err)
w.WriteHeader(500)
io.WriteString(w, "Error reading login.tmpl")
return
}
w.WriteHeader(401)
io.WriteString(w, loginTemplate)
io.WriteString(w, loginTemplate)
return
}
@ -135,26 +135,24 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
return
}
indexTemplate, err := box.String("index.tmpl")
if err != nil {
indexTemplate, err := box.String("index.tmpl")
if err != nil {
w.WriteHeader(500)
io.WriteString(w, "Error reading index.tmpl")
io.WriteString(w, "Error reading index.tmpl")
return
}
}
tmpl, err := template.New("test").Parse(indexTemplate)
if err != nil {
tmpl, err := template.New("test").Parse(indexTemplate)
if err != nil {
w.WriteHeader(500)
log.Println(err)
io.WriteString(w, "Error compiling index.tmpl")
log.Println(err)
io.WriteString(w, "Error compiling index.tmpl")
return
}
}
tmpl.Execute(w, p.tunMan.tunnels)
tmpl.Execute(w, p.tunMan.tunnels)
//io.WriteString(w, indexTemplate)
//io.WriteString(w, indexTemplate)
case "/tunnels":
@ -174,7 +172,7 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
p.handleTunnels(w, r)
case "/delete-tunnel":
token, err := extractToken("access_token", r)
token, err := extractToken("access_token", r)
if err != nil {
w.WriteHeader(401)
w.Write([]byte("No token provided"))
@ -187,7 +185,7 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
return
}
r.ParseForm()
r.ParseForm()
if len(r.Form["host"]) != 1 {
w.WriteHeader(400)
@ -198,7 +196,7 @@ func (p *BoringProxy) handleAdminRequest(w http.ResponseWriter, r *http.Request)
p.tunMan.DeleteTunnel(host)
http.Redirect(w, r, "/", 307)
http.Redirect(w, r, "/", 307)
default:
w.WriteHeader(400)
w.Write([]byte("Invalid endpoint"))
@ -234,49 +232,48 @@ func (p *BoringProxy) handleTunnels(w http.ResponseWriter, r *http.Request) {
func (p *BoringProxy) handleLogin(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
query := r.URL.Query()
key, exists := query["key"]
switch r.Method {
case "GET":
query := r.URL.Query()
key, exists := query["key"]
if !exists {
w.WriteHeader(400)
fmt.Fprintf(w, "Must provide key for verification")
return
}
if !exists {
w.WriteHeader(400)
fmt.Fprintf(w, "Must provide key for verification")
return
}
token, err := p.auth.Verify(key[0])
token, err := p.auth.Verify(key[0])
if err != nil {
w.WriteHeader(400)
fmt.Fprintf(w, "Invalid key")
return
}
if err != nil {
w.WriteHeader(400)
fmt.Fprintf(w, "Invalid key")
return
}
cookie := &http.Cookie{Name: "access_token", Value: token, Secure: true, HttpOnly: true}
http.SetCookie(w, cookie)
cookie := &http.Cookie{Name: "access_token", Value: token, Secure: true, HttpOnly: true}
http.SetCookie(w, cookie)
http.Redirect(w, r, "/", 307)
http.Redirect(w, r, "/", 307)
case "POST":
case "POST":
r.ParseForm()
r.ParseForm()
toEmail, ok := r.Form["email"]
toEmail, ok := r.Form["email"]
if !ok {
w.WriteHeader(400)
w.Write([]byte("Email required for login"))
return
}
if !ok {
w.WriteHeader(400)
w.Write([]byte("Email required for login"))
return
}
// run in goroutine because it can take some time to send the
// email
go p.auth.Login(toEmail[0], p.config)
// run in goroutine because it can take some time to send the
// email
go p.auth.Login(toEmail[0], p.config)
io.WriteString(w, "Check your email to finish logging in")
default:
io.WriteString(w, "Check your email to finish logging in")
default:
w.WriteHeader(405)
w.Write([]byte("Invalid method for login"))
}
@ -284,7 +281,7 @@ func (p *BoringProxy) handleLogin(w http.ResponseWriter, r *http.Request) {
func (p *BoringProxy) handleCreateTunnel(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
r.ParseForm()
if len(r.Form["host"]) != 1 {
w.WriteHeader(400)
@ -307,13 +304,13 @@ func (p *BoringProxy) handleCreateTunnel(w http.ResponseWriter, r *http.Request)
}
err = p.tunMan.SetTunnel(host, port)
if err != nil {
if err != nil {
w.WriteHeader(400)
io.WriteString(w, "Failed to get cert. Ensure your domain is valid")
io.WriteString(w, "Failed to get cert. Ensure your domain is valid")
return
}
}
http.Redirect(w, r, "/", 303)
http.Redirect(w, r, "/", 303)
}
func (p *BoringProxy) handleConnection(clientConn net.Conn) {

View File

@ -1,64 +1,63 @@
package main
import (
"log"
"fmt"
"golang.org/x/crypto/ssh"
"io/ioutil"
"fmt"
"golang.org/x/crypto/ssh"
"io/ioutil"
"log"
)
type BoringProxyClient struct {
}
func NewBoringProxyClient() *BoringProxyClient {
return &BoringProxyClient{}
return &BoringProxyClient{}
}
func (c *BoringProxyClient) Run() {
log.Println("Run client")
log.Println("Run client")
//var hostKey ssh.PublicKey
//var hostKey ssh.PublicKey
config := &ssh.ClientConfig{
config := &ssh.ClientConfig{
User: "user",
Auth: []ssh.AuthMethod{
ssh.Password("yolo"),
ssh.Password("yolo"),
},
//HostKeyCallback: ssh.FixedHostKey(hostKey),
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", "boringproxy.io:2022", config)
client, err := ssh.Dial("tcp", "boringproxy.io:2022", config)
if err != nil {
log.Fatal("Failed to dial: ", err)
}
tunnelRequests := client.HandleChannelOpen("boringproxy-tunnel")
tunnelRequests := client.HandleChannelOpen("boringproxy-tunnel")
for req := range tunnelRequests {
go handleTunnelRequest(req)
}
for req := range tunnelRequests {
go handleTunnelRequest(req)
}
}
func handleTunnelRequest(req ssh.NewChannel) error {
tun, reqs, err := req.Accept()
if err != nil {
return err
}
tun, reqs, err := req.Accept()
if err != nil {
return err
}
go ssh.DiscardRequests(reqs)
go ssh.DiscardRequests(reqs)
port := req.ExtraData()
port := req.ExtraData()
fmt.Println(port)
fmt.Println(port)
data, err := ioutil.ReadAll(tun)
if err != nil {
return err
}
data, err := ioutil.ReadAll(tun)
if err != nil {
return err
}
fmt.Println(string(data))
return nil
fmt.Println(string(data))
return nil
}

38
main.go
View File

@ -1,31 +1,31 @@
package main
import (
"fmt"
"fmt"
"log"
"os"
"os"
)
func main() {
if len(os.Args) < 2 {
fmt.Println("Invalid arguments")
os.Exit(1)
}
if len(os.Args) < 2 {
fmt.Println("Invalid arguments")
os.Exit(1)
}
command := os.Args[1]
command := os.Args[1]
switch command {
case "server":
log.Println("Starting up")
proxy := NewBoringProxy()
proxy.Run()
switch command {
case "server":
log.Println("Starting up")
proxy := NewBoringProxy()
proxy.Run()
case "client":
client := NewBoringProxyClient()
client.Run()
default:
fmt.Println("Invalid command " + command)
os.Exit(1)
}
case "client":
client := NewBoringProxyClient()
client.Run()
default:
fmt.Println("Invalid command " + command)
os.Exit(1)
}
}

View File

@ -1,24 +1,22 @@
package main
import (
"fmt"
"log"
"net"
"io/ioutil"
"golang.org/x/crypto/ssh"
"fmt"
"golang.org/x/crypto/ssh"
"io/ioutil"
"log"
"net"
)
type SshServer struct {
config *ssh.ServerConfig
listener net.Listener
config *ssh.ServerConfig
listener net.Listener
}
func NewSshServer() *SshServer {
config := &ssh.ServerConfig{}
config := &ssh.ServerConfig{}
privateBytes, err := ioutil.ReadFile("id_rsa_boringproxy")
privateBytes, err := ioutil.ReadFile("id_rsa_boringproxy")
if err != nil {
log.Fatal("Failed to load private key: ", err)
}
@ -30,66 +28,66 @@ func NewSshServer() *SshServer {
config.AddHostKey(private)
listener, err := net.Listen("tcp", "0.0.0.0:2022")
listener, err := net.Listen("tcp", "0.0.0.0:2022")
if err != nil {
log.Fatal("failed to listen for connection: ", err)
}
server := &SshServer{config, listener}
server := &SshServer{config, listener}
go server.acceptAll()
go server.acceptAll()
return server
return server
}
func (s *SshServer) acceptAll() {
for {
nConn, err := s.listener.Accept()
if err != nil {
log.Print("failed to accept incoming connection: ", err)
continue
}
for {
nConn, err := s.listener.Accept()
if err != nil {
log.Print("failed to accept incoming connection: ", err)
continue
}
go s.handleServerConn(nConn)
}
go s.handleServerConn(nConn)
}
}
func (s *SshServer) handleServerConn(nConn net.Conn) {
var password string
var password string
s.config.PasswordCallback = func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
password = string(pass)
if c.User() == "user" && string(pass) == "yolo" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
}
conn, chans, reqs, err := ssh.NewServerConn(nConn, s.config)
if err != nil {
log.Print("failed to handshake: ", err)
return
s.config.PasswordCallback = func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
password = string(pass)
if c.User() == "user" && string(pass) == "yolo" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
}
fmt.Println(password)
conn, chans, reqs, err := ssh.NewServerConn(nConn, s.config)
if err != nil {
log.Print("failed to handshake: ", err)
return
}
fmt.Println(password)
go ssh.DiscardRequests(reqs)
go func() {
for newChannel := range chans {
newChannel.Reject(ssh.ResourceShortage, "too bad")
}
}()
go func() {
for newChannel := range chans {
newChannel.Reject(ssh.ResourceShortage, "too bad")
}
}()
ch, cReqs, err := conn.OpenChannel("boringproxy-tunnel", []byte{25, 25})
if err != nil {
log.Print(err)
return
}
ch, cReqs, err := conn.OpenChannel("boringproxy-tunnel", []byte{25, 25})
if err != nil {
log.Print(err)
return
}
go ssh.DiscardRequests(cReqs)
go ssh.DiscardRequests(cReqs)
ch.Write([]byte("Hi there"))
ch.Close()
ch.Write([]byte("Hi there"))
ch.Close()
}

View File

@ -1,19 +1,19 @@
package main
import (
"fmt"
"strings"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"github.com/caddyserver/certmagic"
"golang.org/x/crypto/ssh"
"io/ioutil"
"log"
"strings"
"sync"
"crypto/rsa"
"crypto/rand"
"encoding/pem"
"crypto/x509"
"golang.org/x/crypto/ssh"
)
type Tunnel struct {
@ -27,7 +27,7 @@ func NewTunnels() Tunnels {
}
type TunnelManager struct {
nextPort int
nextPort int
tunnels Tunnels
mutex *sync.Mutex
certConfig *certmagic.Config
@ -57,7 +57,7 @@ func NewTunnelManager(certConfig *certmagic.Config) *TunnelManager {
}
}
nextPort := 9001
nextPort := 9001
mutex := &sync.Mutex{}
return &TunnelManager{nextPort, tunnels, mutex, certConfig}
@ -67,7 +67,7 @@ func (m *TunnelManager) SetTunnel(host string, port int) error {
err := m.certConfig.ManageSync([]string{host})
if err != nil {
log.Println(err)
return errors.New("Failed to get cert")
return errors.New("Failed to get cert")
}
tunnel := &Tunnel{port}
@ -76,36 +76,36 @@ func (m *TunnelManager) SetTunnel(host string, port int) error {
saveJson(m.tunnels, "tunnels.json")
m.mutex.Unlock()
return nil
return nil
}
func (m *TunnelManager) CreateTunnel(domain string) (int, string, error) {
err := m.certConfig.ManageSync([]string{domain})
if err != nil {
log.Println(err)
return 0, "", errors.New("Failed to get cert")
return 0, "", errors.New("Failed to get cert")
}
m.mutex.Lock()
defer m.mutex.Unlock()
_, exists := m.tunnels[domain]
if exists {
return 0, "", errors.New("Tunnel exists for domain " + domain)
}
_, exists := m.tunnels[domain]
if exists {
return 0, "", errors.New("Tunnel exists for domain " + domain)
}
port := m.nextPort
m.nextPort += 1
port := m.nextPort
m.nextPort += 1
tunnel := &Tunnel{port}
m.tunnels[domain] = tunnel
saveJson(m.tunnels, "tunnels.json")
privKey, err := m.addToAuthorizedKeys(port)
if err != nil {
return 0, "", err
}
privKey, err := m.addToAuthorizedKeys(port)
if err != nil {
return 0, "", err
}
return port, privKey, nil
return port, privKey, nil
}
func (m *TunnelManager) DeleteTunnel(host string) {
@ -129,29 +129,29 @@ func (m *TunnelManager) GetPort(serverName string) (int, error) {
func (m *TunnelManager) addToAuthorizedKeys(port int) (string, error) {
akBytes, err := ioutil.ReadFile("/home/anders/.ssh/authorized_keys")
if err != nil {
return "", err
}
akBytes, err := ioutil.ReadFile("/home/anders/.ssh/authorized_keys")
if err != nil {
return "", err
}
akStr := string(akBytes)
akStr := string(akBytes)
pubKey, privKey, err := MakeSSHKeyPair()
if err != nil {
return "", err
}
pubKey, privKey, err := MakeSSHKeyPair()
if err != nil {
return "", err
}
options := fmt.Sprintf(`command="echo This key permits tunnels only",permitopen="fakehost:1",permitlisten="localhost:%d"`, port)
options := fmt.Sprintf(`command="echo This key permits tunnels only",permitopen="fakehost:1",permitlisten="localhost:%d"`, port)
pubKeyNoNewline := pubKey[:len(pubKey) - 1]
newAk := fmt.Sprintf("%s%s %s %s%d\n", akStr, options, pubKeyNoNewline, "boringproxy-", port)
pubKeyNoNewline := pubKey[:len(pubKey)-1]
newAk := fmt.Sprintf("%s%s %s %s%d\n", akStr, options, pubKeyNoNewline, "boringproxy-", port)
err = ioutil.WriteFile("/home/anders/.ssh/authorized_keys", []byte(newAk), 0600)
if err != nil {
return "", err
}
err = ioutil.WriteFile("/home/anders/.ssh/authorized_keys", []byte(newAk), 0600)
if err != nil {
return "", err
}
return privKey, nil
return privKey, nil
}
// Adapted from https://stackoverflow.com/a/34347463/943814
@ -159,27 +159,27 @@ func (m *TunnelManager) addToAuthorizedKeys(port int) (string, error) {
// Public key is encoded in the format for inclusion in an OpenSSH authorized_keys file.
// Private Key generated is PEM encoded
func MakeSSHKeyPair() (string, string, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
return "", "", err
}
privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
return "", "", err
}
// generate and write private key as PEM
var privKeyBuf strings.Builder
// generate and write private key as PEM
var privKeyBuf strings.Builder
privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
if err := pem.Encode(&privKeyBuf, privateKeyPEM); err != nil {
return "", "", err
}
privateKeyPEM := &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(privateKey)}
if err := pem.Encode(&privKeyBuf, privateKeyPEM); err != nil {
return "", "", err
}
// generate and write public key
pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
return "", "", err
}
// generate and write public key
pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
return "", "", err
}
var pubKeyBuf strings.Builder
pubKeyBuf.Write(ssh.MarshalAuthorizedKey(pub))
var pubKeyBuf strings.Builder
pubKeyBuf.Write(ssh.MarshalAuthorizedKey(pub))
return pubKeyBuf.String(), privKeyBuf.String(), nil
return pubKeyBuf.String(), privKeyBuf.String(), nil
}