@@ -3,7 +3,11 @@ package app | |||
import ( | |||
"cwtch.im/cwtch/connectivity/tor" | |||
"cwtch.im/cwtch/peer" | |||
"fmt" | |||
"log" | |||
"os" | |||
"os/user" | |||
"path" | |||
) | |||
// Application is a facade over a cwtchPeer that provides some wrapping logic. | |||
@@ -19,11 +23,10 @@ func (app *Application) NewProfile(name string, filename string, password string | |||
err := profile.Save(filename) | |||
if err == nil { | |||
_, err := tor.NewTorManager(9050, 9051) | |||
err := app.startTor() | |||
if err != nil { | |||
return err | |||
} | |||
go func() { | |||
err := app.Peer.Listen() | |||
if err != nil { | |||
@@ -34,6 +37,38 @@ func (app *Application) NewProfile(name string, filename string, password string | |||
return err | |||
} | |||
func (app *Application) startTor() error { | |||
// Creating a local cwtch tor server config for the user | |||
usr, err := user.Current() | |||
if err != nil { | |||
return err | |||
} | |||
// creating /home/<usr>/.cwtch/torrc file | |||
// SOCKSPort socksPort | |||
// ControlPort controlPort | |||
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 err | |||
} | |||
fmt.Fprintf(file, "SOCKSPort %d\nControlPort %d\n", 9050, 9051) | |||
file.Close() | |||
} | |||
tm, err := tor.NewTorManager(9050, 9051, torrc) | |||
if err != nil { | |||
return err | |||
} | |||
app.TorManager = tm | |||
return nil | |||
} | |||
// SetProfile loads an existing profile from the given filename. | |||
func (app *Application) SetProfile(filename string, password string) error { | |||
profile, err := peer.LoadCwtchPeer(filename, password) | |||
@@ -43,12 +78,10 @@ func (app *Application) SetProfile(filename string, password string) error { | |||
app.Peer = profile | |||
if err == nil { | |||
tm, err := tor.NewTorManager(9050, 9051) | |||
err := app.startTor() | |||
if err != nil { | |||
return err | |||
} | |||
app.TorManager = tm | |||
go func() { | |||
err := app.Peer.Listen() | |||
if err != nil { | |||
@@ -8,15 +8,12 @@ import ( | |||
"net" | |||
"net/http" | |||
"net/url" | |||
"os" | |||
"os/exec" | |||
"os/user" | |||
"path" | |||
"strings" | |||
"time" | |||
) | |||
// Manager checks connectivity of the Tor process used to support Cwtch/ | |||
// Manager checks connectivity of the Tor process used to support Cwtch | |||
type Manager struct { | |||
socksPort int | |||
controlPort int | |||
@@ -24,44 +21,28 @@ type Manager struct { | |||
} | |||
// NewTorManager Instantiates a new connection manager, returns non-nil error if it fails to connect to a tor daemon on the given ports. | |||
func NewTorManager(socksPort int, controlPort int) (*Manager, error) { | |||
func NewTorManager(socksPort int, controlPort int, torrc string) (*Manager, error) { | |||
torManager := new(Manager) | |||
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 | |||
if err == nil { | |||
log.Printf("using existing tor proxy") | |||
return torManager, nil | |||
} | |||
// try to start tor | |||
cmd := exec.Command("tor", "-f", torrc) | |||
log.Printf("starting local tor proxy") | |||
err = cmd.Start() | |||
if err != nil { | |||
log.Printf("starting tor failed %v", err) | |||
return nil, err | |||
} | |||
time.Sleep(time.Second * 5) | |||
torManager.process = cmd | |||
err = torManager.TestConnection() | |||
return torManager, err | |||
} | |||
@@ -0,0 +1,27 @@ | |||
package tor | |||
import ( | |||
"fmt" | |||
"os" | |||
"testing" | |||
) | |||
func TestTorManager(t *testing.T) { | |||
os.Remove("/tmp/torrc") | |||
file, _ := os.Create("/tmp/torrc") | |||
fmt.Fprintf(file, "SOCKSPort %d\nControlPort %d\nDataDirectory /tmp/tor\n", 10050, 10051) | |||
file.Close() | |||
tm, err := NewTorManager(10050, 10051, "/tmp/torrc") | |||
if err != nil { | |||
t.Errorf("creating a new tor manager failed: %v", err) | |||
} else { | |||
tm2, err := NewTorManager(10050, 10051, "/tmp/torrc") | |||
if err != nil { | |||
t.Errorf("creating a new tor manager failed: %v", err) | |||
} | |||
tm2.Shutdown() // should not noop | |||
} | |||
tm.Shutdown() | |||
} |
@@ -170,26 +170,28 @@ func (cp *cwtchPeer) Save(profilefile string) error { | |||
// LoadCwtchPeer loads an existing cwtchPeer from a file. | |||
func LoadCwtchPeer(profilefile string, password string) (CwtchPeerInterface, error) { | |||
encryptedbytes, _ := ioutil.ReadFile(profilefile) | |||
encryptedbytes, err := ioutil.ReadFile(profilefile) | |||
var dkr [32]byte | |||
var salty [128]byte | |||
if err == nil { | |||
var dkr [32]byte | |||
var salty [128]byte | |||
//Separate the salt from the encrypted bytes, then generate the derived key | |||
salt, encryptedbytes := encryptedbytes[0:128], encryptedbytes[128:] | |||
dk := pbkdf2.Key([]byte(password), salt, 4096, 32, sha3.New512) | |||
//Separate the salt from the encrypted bytes, then generate the derived key | |||
salt, encryptedbytes := encryptedbytes[0:128], encryptedbytes[128:] | |||
dk := pbkdf2.Key([]byte(password), salt, 4096, 32, sha3.New512) | |||
//cast to arrays | |||
copy(dkr[:], dk) | |||
copy(salty[:], salt) | |||
//cast to arrays | |||
copy(dkr[:], dk) | |||
copy(salty[:], salt) | |||
cp, err := decryptProfile(encryptedbytes, dkr) | |||
if err == nil { | |||
cp.setup() | |||
cp.profilefile = profilefile | |||
cp.key = dkr | |||
cp.salt = salty | |||
return cp, nil | |||
cp, err := decryptProfile(encryptedbytes, dkr) | |||
if err == nil { | |||
cp.setup() | |||
cp.profilefile = profilefile | |||
cp.key = dkr | |||
cp.salt = salty | |||
return cp, nil | |||
} | |||
} | |||
return nil, err | |||
} | |||
@@ -16,6 +16,7 @@ go test ${1} -coverprofile=server.listen.cover.out -v ./server/listen | |||
go test ${1} -coverprofile=server.send.cover.out -v ./server/send | |||
go test ${1} -coverprofile=server.metrics.cover.out -v ./server/metrics | |||
go test ${1} -coverprofile=server.cover.out -v ./server | |||
go test ${1} -coverprofile=tor.cover.out -v ./connectivity/tor | |||
echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \ | |||
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out | |||
rm -rf *.cover.out |