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

16
auth.go
View File

@ -20,7 +20,7 @@ type Auth struct {
} }
type LoginRequest struct { type LoginRequest struct {
Email string Email string
} }
type Session struct { type Session struct {
@ -109,16 +109,16 @@ func (a *Auth) Verify(key string) (string, error) {
delete(a.pendingRequests, key) delete(a.pendingRequests, key)
token, err := genRandomKey() token, err := genRandomKey()
if err != nil { if err != nil {
return "", errors.New("Error generating key") 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" const chars string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

View File

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

View File

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

38
main.go
View File

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

View File

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

View File

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