forked from cwtch.im/cwtch
Merge branch 'android' of dan/cwtch into master
This commit is contained in:
commit
96b6cf6bb8
|
@ -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]
|
||||
|
|
77
app/app.go
77
app/app.go
|
@ -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 {
|
||||
|
||||
err := app.startTor()
|
||||
if err != nil {
|
||||
return err
|
||||
return app.startPeer()
|
||||
}
|
||||
|
||||
func (app *Application) startPeer() error {
|
||||
go func() {
|
||||
err := app.Peer.Listen()
|
||||
if err != nil {
|
||||
log.Panic(err)
|
||||
e := app.Peer.Listen()
|
||||
if e != nil {
|
||||
log.Panic(e)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PeerRequest attempts to setup peer relationship with the given onion address.`
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
app.Peer.Save()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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…
Reference in New Issue