diff --git a/app/app.go b/app/app.go index e57c666..d18326e 100644 --- a/app/app.go +++ b/app/app.go @@ -8,7 +8,8 @@ import ( // Application is a facade over a cwtchPeer that provides some wrapping logic. type Application struct { - Peer peer.CwtchPeerInterface + Peer peer.CwtchPeerInterface + TorManager *tor.Manager } // NewProfile creates a new cwtchPeer with a given name. @@ -42,10 +43,11 @@ func (app *Application) SetProfile(filename string, password string) error { app.Peer = profile if err == nil { - _, err := tor.NewTorManager(9050, 9051) + tm, err := tor.NewTorManager(9050, 9051) if err != nil { return err } + app.TorManager = tm go func() { err := app.Peer.Listen() diff --git a/app/cli/main.go b/app/cli/main.go index 5e5d678..bc870e0 100644 --- a/app/cli/main.go +++ b/app/cli/main.go @@ -10,6 +10,7 @@ import ( "bytes" "golang.org/x/crypto/ssh/terminal" + "os" "syscall" ) @@ -428,7 +429,16 @@ func main() { } } if profilefile != "" { - app.Peer.Save(profilefile) + if app.Peer != nil { + app.Peer.Save(profilefile) + } } } + + if app.TorManager != nil { + fmt.Println("Shutting down Tor process...") + app.TorManager.Shutdown() + } + os.Exit(0) + } diff --git a/connectivity/tor/tormanager.go b/connectivity/tor/tormanager.go index c62fcc3..ec58591 100644 --- a/connectivity/tor/tormanager.go +++ b/connectivity/tor/tormanager.go @@ -4,9 +4,14 @@ import ( "errors" "fmt" "github.com/yawning/bulb" + "log" "net" "net/http" "net/url" + "os" + "os/exec" + "os/user" + "path" "strings" "time" ) @@ -15,6 +20,7 @@ import ( type Manager struct { socksPort int controlPort int + process *exec.Cmd } // NewTorManager Instantiates a new connection manager, returns non-nil error if it fails to connect to a tor daemon on the given ports. @@ -23,6 +29,39 @@ func NewTorManager(socksPort int, controlPort int) (*Manager, error) { torManager.socksPort = socksPort torManager.controlPort = controlPort err := torManager.TestConnection() + + if err != nil { + + usr, err := user.Current() + if err != nil { + return nil, err + } + + torrc := path.Join(usr.HomeDir, ".cwtch", "torrc") + if _, err := os.Stat(torrc); os.IsNotExist(err) { + + os.MkdirAll(path.Join(usr.HomeDir, ".cwtch"), 0700) + + file, err := os.Create(torrc) + if err != nil { + return nil, err + } + fmt.Fprintf(file, "SOCKSPort %d\nControlPort %d\n", socksPort, controlPort) + file.Close() + } + + cmd := exec.Command("tor", "-f", torrc) + err = cmd.Start() + if err != nil { + return nil, err + } + fmt.Printf("\nWaiting to connect to Tor Proxy...\n") + time.Sleep(time.Second * 5) + torManager.process = cmd + err = torManager.TestConnection() + return torManager, err + } + return torManager, err } @@ -35,6 +74,15 @@ const ( proxyStatusTimeout ) +// Shutdown kills the managed Tor Process +func (tm *Manager) Shutdown() { + if tm.process != nil { + if err := tm.process.Process.Kill(); err != nil { + log.Fatal("failed to kill process: ", err) + } + } +} + // Detect whether a proxy is connectable and is a Tor proxy func checkTorProxy(proxyAddress string) proxyStatus { // A trick to do this without making an outward connection is,