Browse Source

Merge branch 'android' of dan/cwtch into master

pull/94/head
Sarah Jamie Lewis Gogs 1 year ago
parent
commit
96b6cf6bb8
8 changed files with 112 additions and 84 deletions
  1. +1
    -1
      .drone.yml
  2. +39
    -42
      app/app.go
  3. +28
    -18
      app/cli/main.go
  4. +21
    -4
      connectivity/tor/tormanager.go
  5. +7
    -3
      connectivity/tor/tormanager_test.go
  6. +8
    -8
      peer/cwtch_peer.go
  7. +5
    -5
      peer/cwtch_peer_test.go
  8. +3
    -3
      testing/cwtch_peer_server_intergration_test.go

+ 1
- 1
.drone.yml View File

@@ -36,7 +36,7 @@ pipeline:
when:
status: [ success, changed, failure ]
notify-gogs:
image: mindstab/drone-gogs
image: openpriv/drone-gogs
when:
event: pull_request
secrets: [gogs_account_token]


+ 39
- 42
app/app.go View File

@@ -3,10 +3,10 @@ package app
import (
"cwtch.im/cwtch/connectivity/tor"
"cwtch.im/cwtch/peer"
"errors"
"fmt"
"log"
"os"
"os/user"
"path"
)

@@ -14,54 +14,53 @@ import (
type Application struct {
Peer peer.CwtchPeerInterface
TorManager *tor.Manager
directory string
}

// NewApp creates a new app with some environment awareness and initializes a Tor Manager
func NewApp(appDirectory string, torPath string) (*Application, error) {
log.Printf("NewApp(%v, %v)\n", appDirectory, torPath)
app := &Application{Peer: nil, directory: appDirectory}
os.MkdirAll(path.Join(appDirectory, "tor"), 0700)
err := app.startTor(torPath)
if err != nil {
return nil, err
}
return app, nil
}

// NewProfile creates a new cwtchPeer with a given name.
func (app *Application) NewProfile(name string, filename string, password string) error {
profile := peer.NewCwtchPeer(name, password)
app.Peer = profile
err := profile.Save(filename)
func (app *Application) NewProfile(name string, password string) error {
log.Printf("NewProfile(%v, %v)\n", name, password)
if app.Peer != nil {
return errors.New("Profile already created")
}
app.Peer = peer.NewCwtchPeer(name, password, path.Join(app.directory, name+".json"))
err := app.Peer.Save()
if err == nil {

err := app.startTor()
if err != nil {
return err
}
go func() {
err := app.Peer.Listen()
if err != nil {
log.Panic(err)
}
}()
err = app.startPeer()
}
return err
}

func (app *Application) startTor() error {
// startTor will create a local torrc if needed
func (app *Application) startTor(torPath string) 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
// creating $app.directory/torrc file
// SOCKSPort socksPort
// ControlPort controlPort
torrc := path.Join(usr.HomeDir, ".cwtch", "torrc")
torrc := path.Join(app.directory, "tor", "torrc")
if _, err := os.Stat(torrc); os.IsNotExist(err) {

os.MkdirAll(path.Join(usr.HomeDir, ".cwtch"), 0700)

log.Printf("writing torrc to: %v\n", torrc)
file, err := os.Create(torrc)
if err != nil {
return err
}
fmt.Fprintf(file, "SOCKSPort %d\nControlPort %d\n", 9050, 9051)
fmt.Fprintf(file, "SOCKSPort %d\nControlPort %d\nCookieAuthentication 0\nSafeSocks 1\n", 9050, 9051)
file.Close()
}

tm, err := tor.NewTorManager(9050, 9051, torrc)
tm, err := tor.NewTorManager(9050, 9051, torPath, torrc)
if err != nil {
return err
}
@@ -76,20 +75,18 @@ func (app *Application) SetProfile(filename string, password string) error {
return err
}
app.Peer = profile
if err == nil {
return app.startPeer()
}

err := app.startTor()
if err != nil {
return err
func (app *Application) startPeer() error {
go func() {
e := app.Peer.Listen()
if e != nil {
log.Panic(e)
}
go func() {
err := app.Peer.Listen()
if err != nil {
log.Panic(err)
}
}()
}
return err
}()

return nil
}

// PeerRequest attempts to setup peer relationship with the given onion address.`


+ 28
- 18
app/cli/main.go View File

@@ -10,14 +10,18 @@ import (

"bytes"
"golang.org/x/crypto/ssh/terminal"
"log"
"os"
"os/exec"
"os/user"
"path"
"syscall"
)

var app app2.Application
var app *app2.Application

var suggestions = []prompt.Suggest{
{Text: "new-profile", Description: "create a new profile"},
{Text: "new-profile", Description: "create a new profile in ~/.cwtch/$USERNAME.json"},
{Text: "load-profile", Description: "load a new profile"},
{Text: "quit", Description: "quit cwtch"},
{Text: "info", Description: "show user info"},
@@ -37,7 +41,7 @@ var suggestions = []prompt.Suggest{
}

var usages = map[string]string{
"new-profile": "new-profile [name] [filename]",
"new-profile": "new-profile [name]",
"load-profile": "load-profile [filename]",
"quit": "",
"servers": "",
@@ -163,8 +167,18 @@ func main() {
fmt.Printf("%v\n\n", cwtch)

quit := false
app = app2.Application{}
profilefile := ""

torPath, err := exec.LookPath("tor")
if err != nil {
log.Fatal("tor could not be found on this system. Please install it in the system $PATH")
}

usr, err := user.Current()
if err != nil {
log.Fatalf("\nError: could not load current user: %v\n", err)
}

app, err = app2.NewApp(path.Join(usr.HomeDir, ".cwtch"), torPath)
var history []string
for !quit {
profile := "unset"
@@ -181,10 +195,10 @@ func main() {
history = append(history, text)
switch commands[0] {
case "quit":
app.Peer.Save(profilefile)
app.Peer.Save()
quit = true
case "new-profile":
if len(commands) == 3 {
if len(commands) == 2 {
fmt.Print("** WARNING: PASSWORDS CANNOT BE RECOVERED! **\n")

password := ""
@@ -209,8 +223,7 @@ func main() {
if failcount >= 3 {
fmt.Printf("Error creating profile for %v: Your password entries must match!\n", commands[1])
} else {
err := app.NewProfile(commands[1], commands[2], password)
profilefile = commands[2]
err := app.NewProfile(commands[1], password)
if err == nil {
fmt.Printf("\nNew profile created for %v\n", commands[1])
} else {
@@ -224,10 +237,9 @@ func main() {
if len(commands) == 2 {
fmt.Print("Enter a password to decrypt the profile: ")
bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
err = app.SetProfile(commands[1], string(bytePassword))
err = app.SetProfile(commands[1]+".json", string(bytePassword))
if err == nil {
fmt.Printf("\nLoaded profile for %v\n", commands[1])
profilefile = commands[1]
} else {
fmt.Printf("Error loading profile for %v: %v\n", commands[1], err)
}
@@ -288,7 +300,7 @@ func main() {
if err != nil {
fmt.Printf("Error: %v\n", err)
} else {
app.Peer.Save(profilefile)
app.Peer.Save()
group := app.Peer.GetGroup(groupID)
if group == nil {
fmt.Printf("Error: group does not exist\n")
@@ -315,7 +327,7 @@ func main() {
id, _, err := app.Peer.StartGroup(commands[1])
if err == nil {
fmt.Printf("New Group [%v] created for server %v\n", id, commands[1])
app.Peer.Save(profilefile)
app.Peer.Save()
group := app.Peer.GetGroup(id)
if group == nil {
fmt.Printf("Error: group does not exist\n")
@@ -378,7 +390,7 @@ func main() {
fmt.Printf("Error reading timeline from group, usage: %s\n", usages["timeline"])
}
case "save":
app.Peer.Save(profilefile)
app.Peer.Save()
case "help":
for _, command := range suggestions {
fmt.Printf("%-18s%-56s%s\n", command.Text, command.Description, usages[command.Text])
@@ -428,10 +440,8 @@ func main() {
}
}
}
if profilefile != "" {
if app.Peer != nil {
app.Peer.Save(profilefile)
}
if app.Peer != nil {
app.Peer.Save()
}
}



+ 21
- 4
connectivity/tor/tormanager.go View File

@@ -8,7 +8,9 @@ import (
"net"
"net/http"
"net/url"
"os"
"os/exec"
"path"
"strings"
"time"
)
@@ -21,10 +23,11 @@ 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, torrc string) (*Manager, error) {
func NewTorManager(socksPort int, controlPort int, torPath string, torrc string) (*Manager, error) {
torManager := new(Manager)
torManager.socksPort = socksPort
torManager.controlPort = controlPort

err := torManager.TestConnection()

if err == nil {
@@ -33,16 +36,30 @@ func NewTorManager(socksPort int, controlPort int, torrc string) (*Manager, erro
}

// try to start tor
cmd := exec.Command("tor", "-f", torrc)

cmd := exec.Command(torPath, "-f", torrc)

// on Android, home can be set to '/' which is not writeable
if os.Getenv("HOME") == "" {
cmd.Env = append(os.Environ(), fmt.Sprintf("HOME=%s", path.Dir(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()

// for 30 seconds check every 5 if tor is up and working
for i := 0; i < 6; i++ {
time.Sleep(time.Second * 5)
err = torManager.TestConnection()
if err == nil {
break
}
}
return torManager, err
}



+ 7
- 3
connectivity/tor/tormanager_test.go View File

@@ -3,21 +3,25 @@ package tor
import (
"fmt"
"os"
"os/exec"
"testing"
)

func TestTorManager(t *testing.T) {

tor, err := exec.LookPath("tor")
if err != nil {
t.Errorf("tor not found in PATH")
}
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")
tm, err := NewTorManager(10050, 10051, tor, "/tmp/torrc")
if err != nil {
t.Errorf("creating a new tor manager failed: %v", err)
} else {

tm2, err := NewTorManager(10050, 10051, "/tmp/torrc")
tm2, err := NewTorManager(10050, 10051, tor, "/tmp/torrc")
if err != nil {
t.Errorf("creating a new tor manager failed: %v", err)
}


+ 8
- 8
peer/cwtch_peer.go View File

@@ -43,7 +43,7 @@ type cwtchPeer struct {
// CwtchPeerInterface provides us with a way of testing systems built on top of cwtch without having to
// directly implement a cwtchPeer.
type CwtchPeerInterface interface {
Save(string) error
Save() error
PeerWithOnion(string)
InviteOnionToGroup(string, string) error

@@ -145,8 +145,9 @@ func (cp *cwtchPeer) setup() {
}

// NewCwtchPeer creates and returns a new cwtchPeer with the given name.
func NewCwtchPeer(name string, password string) CwtchPeerInterface {
func NewCwtchPeer(name string, password string, profilefile string) CwtchPeerInterface {
cp := new(cwtchPeer)
cp.profilefile = profilefile
cp.Profile = model.GenerateNewProfile(name)
cp.setup()
key, salt := createKey(password)
@@ -156,14 +157,13 @@ func NewCwtchPeer(name string, password string) CwtchPeerInterface {
}

// Save saves the cwtchPeer profile state to a file.
func (cp *cwtchPeer) Save(profilefile string) error {
func (cp *cwtchPeer) Save() error {
cp.mutex.Lock()
encryptedbytes := encryptProfile(cp, cp.key)

// the salt for the derived key is appended to the front of the file
encryptedbytes = append(cp.salt[:], encryptedbytes...)
err := ioutil.WriteFile(profilefile, encryptedbytes, 0600)
cp.profilefile = profilefile
err := ioutil.WriteFile(cp.profilefile, encryptedbytes, 0600)
cp.mutex.Unlock()
return err
}
@@ -171,7 +171,6 @@ func (cp *cwtchPeer) Save(profilefile string) error {
// LoadCwtchPeer loads an existing cwtchPeer from a file.
func LoadCwtchPeer(profilefile string, password string) (CwtchPeerInterface, error) {
encryptedbytes, err := ioutil.ReadFile(profilefile)

if err == nil {
var dkr [32]byte
var salty [128]byte
@@ -184,7 +183,8 @@ func LoadCwtchPeer(profilefile string, password string) (CwtchPeerInterface, err
copy(dkr[:], dk)
copy(salty[:], salt)

cp, err := decryptProfile(encryptedbytes, dkr)
var cp *cwtchPeer
cp, err = decryptProfile(encryptedbytes, dkr)
if err == nil {
cp.setup()
cp.profilefile = profilefile
@@ -429,7 +429,7 @@ type CwtchPeerHandler struct {
func (cph *CwtchPeerHandler) ClientIdentity(ci *protocol.CwtchIdentity) {
log.Printf("Received Client Identity from %v %v\n", cph.Onion, ci.String())
cph.Peer.Profile.AddCwtchIdentity(cph.Onion, ci)
cph.Peer.Save(cph.Peer.profilefile)
cph.Peer.Save()
}

// HandleGroupInvite handles incoming GroupInvites


+ 5
- 5
peer/cwtch_peer_test.go View File

@@ -6,10 +6,10 @@ import (

func TestCwtchPeerGenerate(t *testing.T) {

alice := NewCwtchPeer("alice", "testpass")
alice.Save("./test_profile")
alice := NewCwtchPeer("alice", "testpass", "./alice.json")
alice.Save()

aliceLoaded, err := LoadCwtchPeer("./test_profile", "testpass")
aliceLoaded, err := LoadCwtchPeer("./alice.json", "testpass")
if err != nil || aliceLoaded.GetProfile().Name != "alice" {
t.Errorf("something went wrong saving and loading profiles %v %v", err, aliceLoaded)
}
@@ -26,8 +26,8 @@ func TestCwtchPeerGenerate(t *testing.T) {

func TestTrustPeer(t *testing.T) {
groupName := "test.server"
alice := NewCwtchPeer("alice", "alicepass")
bob := NewCwtchPeer("bob", "bobpass")
alice := NewCwtchPeer("alice", "alicepass", "")
bob := NewCwtchPeer("bob", "bobpass", "")

bobOnion := bob.GetProfile().Onion
aliceOnion := alice.GetProfile().Onion


+ 3
- 3
testing/cwtch_peer_server_intergration_test.go View File

@@ -143,17 +143,17 @@ func TestCwtchPeerIntegration(t *testing.T) {
// ***** Peer setup *****

fmt.Println("Creating Alice...")
alice := peer.NewCwtchPeer("Alice", "alicepass")
alice := peer.NewCwtchPeer("Alice", "alicepass", "")
go alice.Listen()
fmt.Println("Alice created:", alice.GetProfile().Onion)

fmt.Println("Creating Bob...")
bob := peer.NewCwtchPeer("Bob", "bobpass")
bob := peer.NewCwtchPeer("Bob", "bobpass", "")
go bob.Listen()
fmt.Println("Bob created:", bob.GetProfile().Onion)

fmt.Println("Creating Carol...")
carol := peer.NewCwtchPeer("Carol", "carolpass")
carol := peer.NewCwtchPeer("Carol", "carolpass", "")
go carol.Listen()
fmt.Println("Carol created:", carol.GetProfile().Onion)



Loading…
Cancel
Save