Following libricochetgo's migration to bine and a generic Mixnet
interface.
This commit is contained in:
parent
07ffd780b0
commit
85a2c44891
65
app/app.go
65
app/app.go
|
@ -2,12 +2,12 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"cwtch.im/cwtch/connectivity/tor"
|
|
||||||
"cwtch.im/cwtch/peer"
|
"cwtch.im/cwtch/peer"
|
||||||
"cwtch.im/cwtch/storage"
|
"cwtch.im/cwtch/storage"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
type application struct {
|
type application struct {
|
||||||
peers map[string]peer.CwtchPeer
|
peers map[string]peer.CwtchPeer
|
||||||
torManager *tor.Manager
|
mn connectivity.Mixnet
|
||||||
directory string
|
directory string
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
primaryonion string
|
primaryonion string
|
||||||
|
@ -35,23 +35,17 @@ type Application interface {
|
||||||
GetPeer(onion string) peer.CwtchPeer
|
GetPeer(onion string) peer.CwtchPeer
|
||||||
ListPeers() map[string]string
|
ListPeers() map[string]string
|
||||||
|
|
||||||
GetTorStatus() (map[string]string, error)
|
//GetTorStatus() (map[string]string, error)
|
||||||
|
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
||||||
func NewApp(appDirectory string, torPath string) (Application, error) {
|
func NewApp(mn connectivity.Mixnet, appDirectory string) Application {
|
||||||
log.Printf("NewApp(%v, %v)\n", appDirectory, torPath)
|
log.Printf("NewApp(%v)\n", appDirectory)
|
||||||
app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory}
|
app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory, mn: mn}
|
||||||
os.MkdirAll(path.Join(appDirectory, "tor"), 0700)
|
|
||||||
os.Mkdir(path.Join(app.directory, "profiles"), 0700)
|
os.Mkdir(path.Join(app.directory, "profiles"), 0700)
|
||||||
|
return app
|
||||||
err := app.startTor(torPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return app, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateRandomFilename() string {
|
func generateRandomFilename() string {
|
||||||
|
@ -78,7 +72,8 @@ func (app *application) CreatePeer(name string, password string) (peer.CwtchPeer
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
app.startPeer(p)
|
p.Init(app.mn)
|
||||||
|
p.Listen()
|
||||||
_, exists := app.peers[p.GetProfile().Onion]
|
_, exists := app.peers[p.GetProfile().Onion]
|
||||||
if exists {
|
if exists {
|
||||||
p.Shutdown()
|
p.Shutdown()
|
||||||
|
@ -104,7 +99,6 @@ func (app *application) LoadProfiles(password string) error {
|
||||||
|
|
||||||
p, err := fileStore.Load()
|
p, err := fileStore.Load()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +108,8 @@ func (app *application) LoadProfiles(password string) error {
|
||||||
log.Printf("Error: profile for onion %v already exists", p.GetProfile().Onion)
|
log.Printf("Error: profile for onion %v already exists", p.GetProfile().Onion)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
app.startPeer(p)
|
p.Init(app.mn)
|
||||||
|
p.Listen()
|
||||||
app.mutex.Lock()
|
app.mutex.Lock()
|
||||||
app.peers[p.GetProfile().Onion] = p
|
app.peers[p.GetProfile().Onion] = p
|
||||||
app.storage[p.GetProfile().Onion] = fileStore
|
app.storage[p.GetProfile().Onion] = fileStore
|
||||||
|
@ -126,40 +121,6 @@ func (app *application) LoadProfiles(password string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
// creating $app.directory/torrc file
|
|
||||||
// SOCKSPort socksPort
|
|
||||||
// ControlPort controlPort
|
|
||||||
torrc := path.Join(app.directory, "tor", "torrc")
|
|
||||||
if _, err := os.Stat(torrc); os.IsNotExist(err) {
|
|
||||||
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\nCookieAuthentication 0\nSafeSocks 1\n", 9050, 9051)
|
|
||||||
file.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
tm, err := tor.NewTorManager(9050, 9051, torPath, torrc)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
app.torManager = tm
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app *application) startPeer(peer peer.CwtchPeer) {
|
|
||||||
go func() {
|
|
||||||
e := peer.Listen()
|
|
||||||
if e != nil {
|
|
||||||
log.Fatalf("ERROR: peer %v has crashed with: %v\n", peer.GetProfile().Onion, e)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListPeers returns a map of onions to their profile's Name
|
// ListPeers returns a map of onions to their profile's Name
|
||||||
func (app *application) ListPeers() map[string]string {
|
func (app *application) ListPeers() map[string]string {
|
||||||
keys := map[string]string{}
|
keys := map[string]string{}
|
||||||
|
@ -182,15 +143,15 @@ func (app *application) GetPeer(onion string) peer.CwtchPeer {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// GetTorStatus returns tor control port bootstrap-phase status info in a map
|
// GetTorStatus returns tor control port bootstrap-phase status info in a map
|
||||||
func (app *application) GetTorStatus() (map[string]string, error) {
|
func (app *application) GetTorStatus() (map[string]string, error) {
|
||||||
return app.torManager.GetStatus()
|
return app.torManager.GetStatus()
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// Shutdown shutsdown all peers of an app and then the tormanager
|
// Shutdown shutsdown all peers of an app and then the tormanager
|
||||||
func (app *application) Shutdown() {
|
func (app *application) Shutdown() {
|
||||||
for _, peer := range app.peers {
|
for _, peer := range app.peers {
|
||||||
peer.Shutdown()
|
peer.Shutdown()
|
||||||
}
|
}
|
||||||
app.torManager.Shutdown()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ import (
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/peer/connections"
|
"cwtch.im/cwtch/peer/connections"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"github.com/c-bata/go-prompt"
|
"github.com/c-bata/go-prompt"
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/crypto/ssh/terminal"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"os/user"
|
"os/user"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -250,17 +250,16 @@ func main() {
|
||||||
|
|
||||||
quit := false
|
quit := false
|
||||||
|
|
||||||
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()
|
usr, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("\nError: could not load current user: %v\n", err)
|
log.Fatalf("\nError: could not load current user: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app, err = app2.NewApp(path.Join(usr.HomeDir, ".cwtch"), torPath)
|
mn, err := connectivity.StartTor(path.Join(usr.HomeDir, ".cwtch"), "")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("\nError connecting to Tor: %v\n", err)
|
||||||
|
}
|
||||||
|
app = app2.NewApp(mn, path.Join(usr.HomeDir, ".cwtch"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Error initializing application: %v", err)
|
log.Fatalf("Error initializing application: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -307,6 +306,12 @@ func main() {
|
||||||
quit = true
|
quit = true
|
||||||
case "/new-profile":
|
case "/new-profile":
|
||||||
if len(commands) == 2 {
|
if len(commands) == 2 {
|
||||||
|
name := strings.Trim(commands[1], " ")
|
||||||
|
if name == "" {
|
||||||
|
fmt.Printf("Error creating profile, usage: %v\n", usages[commands[0]])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Print("** WARNING: PASSWORDS CANNOT BE RECOVERED! **\n")
|
fmt.Print("** WARNING: PASSWORDS CANNOT BE RECOVERED! **\n")
|
||||||
|
|
||||||
password := ""
|
password := ""
|
||||||
|
@ -329,17 +334,17 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if failcount >= 3 {
|
if failcount >= 3 {
|
||||||
fmt.Printf("Error creating profile for %v: Your password entries must match!\n", commands[1])
|
fmt.Printf("Error creating profile for %v: Your password entries must match!\n", name)
|
||||||
} else {
|
} else {
|
||||||
p, err := app.CreatePeer(commands[1], password)
|
p, err := app.CreatePeer(name, password)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
stopGroupFollow()
|
stopGroupFollow()
|
||||||
fmt.Printf("\nNew profile created for %v\n", commands[1])
|
fmt.Printf("\nNew profile created for %v\n", name)
|
||||||
peer = p
|
peer = p
|
||||||
suggestions = append(suggestionsBase, suggestionsSelectedProfile...)
|
suggestions = append(suggestionsBase, suggestionsSelectedProfile...)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("\nError creating profile for %v: %v\n", commands[1], err)
|
fmt.Printf("\nError creating profile for %v: %v\n", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -597,6 +602,6 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Shutdown()
|
app.Shutdown()
|
||||||
|
mn.Close()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,168 +0,0 @@
|
||||||
package tor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/yawning/bulb"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Manager checks connectivity of the Tor process used to support Cwtch
|
|
||||||
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.
|
|
||||||
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 {
|
|
||||||
log.Printf("using existing tor proxy")
|
|
||||||
return torManager, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to start tor
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type proxyStatus int
|
|
||||||
|
|
||||||
const (
|
|
||||||
proxyStatusOK proxyStatus = iota
|
|
||||||
proxyStatusWrongType
|
|
||||||
proxyStatusCannotConnect
|
|
||||||
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,
|
|
||||||
// paradoxically, to try to open it as http.
|
|
||||||
// This is documented in section 4 here: https://github.com/torproject/torspec/blob/master/socks-extensions.txt
|
|
||||||
client := &http.Client{Timeout: 2 * time.Second}
|
|
||||||
response, err := client.Get("http://" + proxyAddress + "/")
|
|
||||||
if err != nil {
|
|
||||||
switch t := err.(type) {
|
|
||||||
case *url.Error:
|
|
||||||
switch t.Err.(type) {
|
|
||||||
case *net.OpError: // Network-level error. Will in turn contain a os.SyscallError
|
|
||||||
return proxyStatusCannotConnect
|
|
||||||
default:
|
|
||||||
// http.error unfortunately not exported, need to match on string
|
|
||||||
// net/http: request canceled
|
|
||||||
if strings.Index(t.Err.Error(), "request canceled") != -1 {
|
|
||||||
return proxyStatusTimeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Protocol-level errors mean that http failed, so it's not Tor
|
|
||||||
return proxyStatusWrongType
|
|
||||||
}
|
|
||||||
defer response.Body.Close()
|
|
||||||
if response.Status != "501 Tor is not an HTTP Proxy" {
|
|
||||||
return proxyStatusWrongType
|
|
||||||
}
|
|
||||||
return proxyStatusOK
|
|
||||||
}
|
|
||||||
|
|
||||||
func proxyStatusMessage(status proxyStatus) string {
|
|
||||||
switch status {
|
|
||||||
case proxyStatusWrongType:
|
|
||||||
return "Proxy specified is not a Tor proxy"
|
|
||||||
case proxyStatusCannotConnect:
|
|
||||||
return "Cannot connect to Tor proxy"
|
|
||||||
case proxyStatusTimeout:
|
|
||||||
return "Proxy timeout"
|
|
||||||
default:
|
|
||||||
return "Unknown proxy error"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestConnection returns nil if both the socks and control ports of the Tor connection are active, otherwise it returns an error.
|
|
||||||
func (tm *Manager) TestConnection() error {
|
|
||||||
proxyStatus := checkTorProxy(fmt.Sprintf("127.0.0.1:%d", tm.socksPort))
|
|
||||||
controlAddress := fmt.Sprintf("127.0.0.1:%d", tm.controlPort)
|
|
||||||
if proxyStatus == proxyStatusOK {
|
|
||||||
c, err := bulb.Dial("tcp4", controlAddress)
|
|
||||||
if c != nil {
|
|
||||||
c.Close()
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("could not connect to Tor Control Port %v %v", tm.controlPort, err)
|
|
||||||
}
|
|
||||||
return errors.New(proxyStatusMessage(proxyStatus))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStatus returns tor control port bootstrap-phase status info in a map
|
|
||||||
func (tm *Manager) GetStatus() (map[string]string, error) {
|
|
||||||
controlAddress := fmt.Sprintf("127.0.0.1:%d", tm.controlPort)
|
|
||||||
c, err := bulb.Dial("tcp4", controlAddress)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer c.Close()
|
|
||||||
c.Request("AUTHENTICATE \"\"")
|
|
||||||
resp, err := c.Request("GETINFO status/bootstrap-phase")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
lines := strings.SplitN(resp.RawLines[0], " ", 5)
|
|
||||||
var resps = make(map[string]string)
|
|
||||||
for _, l := range lines {
|
|
||||||
kv := strings.Split(l, "=")
|
|
||||||
if len(kv) == 2 {
|
|
||||||
resps[kv[0]] = kv[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resps, nil
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
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, tor, "/tmp/torrc")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("creating a new tor manager failed: %v", err)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
tm2, err := NewTorManager(10050, 10051, tor, "/tmp/torrc")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("creating a new tor manager failed: %v", err)
|
|
||||||
}
|
|
||||||
tm2.Shutdown() // should not noop
|
|
||||||
}
|
|
||||||
tm.Shutdown()
|
|
||||||
}
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -14,11 +15,13 @@ type Manager struct {
|
||||||
serverConnections map[string]*PeerServerConnection
|
serverConnections map[string]*PeerServerConnection
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
breakChannel chan bool
|
breakChannel chan bool
|
||||||
|
mn connectivity.Mixnet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConnectionsManager creates a new instance of Manager.
|
// NewConnectionsManager creates a new instance of Manager.
|
||||||
func NewConnectionsManager() *Manager {
|
func NewConnectionsManager(mn connectivity.Mixnet) *Manager {
|
||||||
m := new(Manager)
|
m := new(Manager)
|
||||||
|
m.mn = mn
|
||||||
m.peerConnections = make(map[string]*PeerPeerConnection)
|
m.peerConnections = make(map[string]*PeerPeerConnection)
|
||||||
m.serverConnections = make(map[string]*PeerServerConnection)
|
m.serverConnections = make(map[string]*PeerServerConnection)
|
||||||
m.breakChannel = make(chan bool)
|
m.breakChannel = make(chan bool)
|
||||||
|
@ -32,7 +35,7 @@ func (m *Manager) ManagePeerConnection(host string, profile *model.Profile, data
|
||||||
|
|
||||||
_, exists := m.peerConnections[host]
|
_, exists := m.peerConnections[host]
|
||||||
if !exists {
|
if !exists {
|
||||||
ppc := NewPeerPeerConnection(host, profile, dataHandler, aif)
|
ppc := NewPeerPeerConnection(m.mn, host, profile, dataHandler, aif)
|
||||||
go ppc.Run()
|
go ppc.Run()
|
||||||
m.peerConnections[host] = ppc
|
m.peerConnections[host] = ppc
|
||||||
return ppc
|
return ppc
|
||||||
|
@ -46,7 +49,7 @@ func (m *Manager) ManageServerConnection(host string, handler func(string, *prot
|
||||||
|
|
||||||
_, exists := m.serverConnections[host]
|
_, exists := m.serverConnections[host]
|
||||||
if !exists {
|
if !exists {
|
||||||
psc := NewPeerServerConnection(host)
|
psc := NewPeerServerConnection(m.mn, host)
|
||||||
go psc.Run()
|
go psc.Run()
|
||||||
psc.GroupMessageHandler = handler
|
psc.GroupMessageHandler = handler
|
||||||
m.serverConnections[host] = psc
|
m.serverConnections[host] = psc
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package connections
|
package connections
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConnectionsManager(t *testing.T) {
|
func TestConnectionsManager(t *testing.T) {
|
||||||
// TODO We need to encapsulate connections behind a well defined interface for tesintg
|
// TODO We need to encapsulate connections behind a well defined interface for tesintg
|
||||||
NewConnectionsManager()
|
NewConnectionsManager(connectivity.LocalProvider())
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
@ -22,11 +23,13 @@ type PeerPeerConnection struct {
|
||||||
profile *model.Profile
|
profile *model.Profile
|
||||||
dataHandler func(string, []byte) []byte
|
dataHandler func(string, []byte) []byte
|
||||||
aif application.ApplicationInstanceFactory
|
aif application.ApplicationInstanceFactory
|
||||||
|
mn connectivity.Mixnet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPeerPeerConnection creates a new peer connection for the given hostname and profile.
|
// NewPeerPeerConnection creates a new peer connection for the given hostname and profile.
|
||||||
func NewPeerPeerConnection(peerhostname string, profile *model.Profile, dataHandler func(string, []byte) []byte, aif application.ApplicationInstanceFactory) *PeerPeerConnection {
|
func NewPeerPeerConnection(mn connectivity.Mixnet, peerhostname string, profile *model.Profile, dataHandler func(string, []byte) []byte, aif application.ApplicationInstanceFactory) *PeerPeerConnection {
|
||||||
ppc := new(PeerPeerConnection)
|
ppc := new(PeerPeerConnection)
|
||||||
|
ppc.mn = mn
|
||||||
ppc.PeerHostname = peerhostname
|
ppc.PeerHostname = peerhostname
|
||||||
ppc.profile = profile
|
ppc.profile = profile
|
||||||
ppc.dataHandler = dataHandler
|
ppc.dataHandler = dataHandler
|
||||||
|
@ -107,7 +110,7 @@ func (ppc *PeerPeerConnection) WaitTilAuthenticated() {
|
||||||
// Run manages the setup and teardown of a peer->peer connection
|
// Run manages the setup and teardown of a peer->peer connection
|
||||||
func (ppc *PeerPeerConnection) Run() error {
|
func (ppc *PeerPeerConnection) Run() error {
|
||||||
ppc.state = CONNECTING
|
ppc.state = CONNECTING
|
||||||
rc, err := goricochet.Open(ppc.PeerHostname)
|
rc, err := goricochet.Open(ppc.mn, ppc.PeerHostname)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
rc.TraceLog(false)
|
rc.TraceLog(false)
|
||||||
ppc.connection = rc
|
ppc.connection = rc
|
||||||
|
|
|
@ -5,10 +5,12 @@ import (
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/peer/peer"
|
"cwtch.im/cwtch/peer/peer"
|
||||||
"cwtch.im/cwtch/protocol"
|
"cwtch.im/cwtch/protocol"
|
||||||
|
"fmt"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go"
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
"net"
|
"net"
|
||||||
|
@ -59,13 +61,14 @@ func TestPeerPeerConnection(t *testing.T) {
|
||||||
|
|
||||||
profile := model.GenerateNewProfile("alice")
|
profile := model.GenerateNewProfile("alice")
|
||||||
hostname := identity.Hostname()
|
hostname := identity.Hostname()
|
||||||
ppc := NewPeerPeerConnection("127.0.0.1:5452|"+hostname, profile, nil, application.ApplicationInstanceFactory{})
|
ppc := NewPeerPeerConnection(connectivity.LocalProvider(), "127.0.0.1:5452|"+hostname, profile, nil, application.ApplicationInstanceFactory{})
|
||||||
|
|
||||||
tp := new(TestPeer)
|
tp := new(TestPeer)
|
||||||
tp.Init()
|
tp.Init()
|
||||||
go runtestpeer(t, tp, identity)
|
go runtestpeer(t, tp, identity)
|
||||||
state := ppc.GetState()
|
state := ppc.GetState()
|
||||||
if state != DISCONNECTED {
|
if state != DISCONNECTED {
|
||||||
|
fmt.Println("ERROR state should be disconnected")
|
||||||
t.Errorf("new connections should start in disconnected state")
|
t.Errorf("new connections should start in disconnected state")
|
||||||
}
|
}
|
||||||
go ppc.Run()
|
go ppc.Run()
|
||||||
|
@ -80,5 +83,4 @@ func TestPeerPeerConnection(t *testing.T) {
|
||||||
if tp.ReceivedGroupInvite == false {
|
if tp.ReceivedGroupInvite == false {
|
||||||
t.Errorf("should have received an group invite packet")
|
t.Errorf("should have received an group invite packet")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go"
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
"log"
|
"log"
|
||||||
|
@ -22,13 +23,15 @@ type PeerServerConnection struct {
|
||||||
Server string
|
Server string
|
||||||
state ConnectionState
|
state ConnectionState
|
||||||
connection *connection.Connection
|
connection *connection.Connection
|
||||||
|
mn connectivity.Mixnet
|
||||||
|
|
||||||
GroupMessageHandler func(string, *protocol.GroupMessage)
|
GroupMessageHandler func(string, *protocol.GroupMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPeerServerConnection creates a new Peer->Server outbound connection
|
// NewPeerServerConnection creates a new Peer->Server outbound connection
|
||||||
func NewPeerServerConnection(serverhostname string) *PeerServerConnection {
|
func NewPeerServerConnection(mn connectivity.Mixnet, serverhostname string) *PeerServerConnection {
|
||||||
psc := new(PeerServerConnection)
|
psc := new(PeerServerConnection)
|
||||||
|
psc.mn = mn
|
||||||
psc.Server = serverhostname
|
psc.Server = serverhostname
|
||||||
psc.Init()
|
psc.Init()
|
||||||
return psc
|
return psc
|
||||||
|
@ -52,7 +55,7 @@ func (psc *PeerServerConnection) WaitTilAuthenticated() {
|
||||||
// Run manages the setup and teardown of a peer server connection
|
// Run manages the setup and teardown of a peer server connection
|
||||||
func (psc *PeerServerConnection) Run() error {
|
func (psc *PeerServerConnection) Run() error {
|
||||||
log.Printf("Connecting to %v", psc.Server)
|
log.Printf("Connecting to %v", psc.Server)
|
||||||
rc, err := goricochet.Open(psc.Server)
|
rc, err := goricochet.Open(psc.mn, psc.Server)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
rc.TraceLog(true)
|
rc.TraceLog(true)
|
||||||
psc.connection = rc
|
psc.connection = rc
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go"
|
"git.openprivacy.ca/openprivacy/libricochet-go"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"golang.org/x/crypto/ed25519"
|
"golang.org/x/crypto/ed25519"
|
||||||
"net"
|
"net"
|
||||||
|
@ -72,7 +73,7 @@ func TestPeerServerConnection(t *testing.T) {
|
||||||
go runtestserver(t, ts, identity)
|
go runtestserver(t, ts, identity)
|
||||||
onionAddr := identity.Hostname()
|
onionAddr := identity.Hostname()
|
||||||
|
|
||||||
psc := NewPeerServerConnection("127.0.0.1:5451|" + onionAddr)
|
psc := NewPeerServerConnection(connectivity.LocalProvider(), "127.0.0.1:5451|"+onionAddr)
|
||||||
numcalls := 0
|
numcalls := 0
|
||||||
psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) {
|
psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) {
|
||||||
numcalls++
|
numcalls++
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
@ -19,6 +20,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// cwtchPeer manages incoming and outgoing connections and all processing for a Cwtch cwtchPeer
|
// cwtchPeer manages incoming and outgoing connections and all processing for a Cwtch cwtchPeer
|
||||||
|
@ -26,17 +28,19 @@ type cwtchPeer struct {
|
||||||
connection.AutoConnectionHandler
|
connection.AutoConnectionHandler
|
||||||
Profile *model.Profile
|
Profile *model.Profile
|
||||||
app *application.RicochetApplication
|
app *application.RicochetApplication
|
||||||
|
mn connectivity.Mixnet
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
connectionsManager *connections.Manager
|
connectionsManager *connections.Manager
|
||||||
dataHandler func(string, []byte) []byte
|
dataHandler func(string, []byte) []byte
|
||||||
//handlers map[string]func(*application.ApplicationInstance) func() channels.Handler
|
//handlers map[string]func(*application.ApplicationInstance) func() channels.Handler
|
||||||
aif application.ApplicationInstanceFactory
|
aif application.ApplicationInstanceFactory
|
||||||
|
shutdown bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// CwtchPeer provides us with a way of testing systems built on top of cwtch without having to
|
// CwtchPeer provides us with a way of testing systems built on top of cwtch without having to
|
||||||
// directly implement a cwtchPeer.
|
// directly implement a cwtchPeer.
|
||||||
type CwtchPeer interface {
|
type CwtchPeer interface {
|
||||||
Init()
|
Init(connectivity.Mixnet)
|
||||||
PeerWithOnion(string) *connections.PeerPeerConnection
|
PeerWithOnion(string) *connections.PeerPeerConnection
|
||||||
InviteOnionToGroup(string, string) error
|
InviteOnionToGroup(string, string) error
|
||||||
|
|
||||||
|
@ -66,7 +70,7 @@ type CwtchPeer interface {
|
||||||
SetApplicationInstanceFactory(factory application.ApplicationInstanceFactory)
|
SetApplicationInstanceFactory(factory application.ApplicationInstanceFactory)
|
||||||
SetPeerDataHandler(func(string, []byte) []byte)
|
SetPeerDataHandler(func(string, []byte) []byte)
|
||||||
|
|
||||||
Listen() error
|
Listen()
|
||||||
Shutdown()
|
Shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +78,7 @@ type CwtchPeer interface {
|
||||||
func NewCwtchPeer(name string) CwtchPeer {
|
func NewCwtchPeer(name string) CwtchPeer {
|
||||||
cp := new(cwtchPeer)
|
cp := new(cwtchPeer)
|
||||||
cp.Profile = model.GenerateNewProfile(name)
|
cp.Profile = model.GenerateNewProfile(name)
|
||||||
cp.Init()
|
cp.shutdown = false
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,13 +86,13 @@ func NewCwtchPeer(name string) CwtchPeer {
|
||||||
func FromProfile(profile *model.Profile) CwtchPeer {
|
func FromProfile(profile *model.Profile) CwtchPeer {
|
||||||
cp := new(cwtchPeer)
|
cp := new(cwtchPeer)
|
||||||
cp.Profile = profile
|
cp.Profile = profile
|
||||||
cp.Init()
|
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init instantiates a cwtchPeer
|
// Init instantiates a cwtchPeer
|
||||||
func (cp *cwtchPeer) Init() {
|
func (cp *cwtchPeer) Init(mn connectivity.Mixnet) {
|
||||||
cp.connectionsManager = connections.NewConnectionsManager()
|
cp.mn = mn
|
||||||
|
cp.connectionsManager = connections.NewConnectionsManager(cp.mn)
|
||||||
go cp.connectionsManager.AttemptReconnections()
|
go cp.connectionsManager.AttemptReconnections()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,11 +299,25 @@ func (cp *cwtchPeer) ContactRequest(name string, message string) string {
|
||||||
return "Accepted"
|
return "Accepted"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cp *cwtchPeer) Listen() {
|
||||||
|
go func() {
|
||||||
|
for !cp.shutdown {
|
||||||
|
e := cp.listenFn()
|
||||||
|
if e != nil {
|
||||||
|
// TODO: was panic, then fatal
|
||||||
|
fmt.Printf("ERROR: peer %v has crashed with: %v\n", cp.GetProfile().Onion, e)
|
||||||
|
}
|
||||||
|
// listenFn failed, wait 5 seconds and try again
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// Listen sets up an onion listener to process incoming cwtch messages
|
// Listen sets up an onion listener to process incoming cwtch messages
|
||||||
func (cp *cwtchPeer) Listen() error {
|
func (cp *cwtchPeer) listenFn() error {
|
||||||
cwtchpeer := new(application.RicochetApplication)
|
ra := new(application.RicochetApplication)
|
||||||
l, err := application.SetupOnionV3("127.0.0.1:9051", "tcp4", "", cp.Profile.Ed25519PrivateKey, cp.GetProfile().Onion, 9878)
|
onionService, err := cp.mn.Listen(cp.Profile.Ed25519PrivateKey, application.RicochetPort)
|
||||||
if err != nil && fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision" {
|
if err != nil /*&& fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision"*/ {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +325,7 @@ func (cp *cwtchPeer) Listen() error {
|
||||||
af.Init()
|
af.Init()
|
||||||
af.AddHandler("im.cwtch.peer", func(rai *application.ApplicationInstance) func() channels.Handler {
|
af.AddHandler("im.cwtch.peer", func(rai *application.ApplicationInstance) func() channels.Handler {
|
||||||
cpi := new(CwtchPeerInstance)
|
cpi := new(CwtchPeerInstance)
|
||||||
cpi.Init(rai, cwtchpeer)
|
cpi.Init(rai, ra)
|
||||||
return func() channels.Handler {
|
return func() channels.Handler {
|
||||||
cpc := new(peer.CwtchPeerChannel)
|
cpc := new(peer.CwtchPeerChannel)
|
||||||
cpc.Handler = &CwtchPeerHandler{Onion: rai.RemoteHostname, Peer: cp}
|
cpc.Handler = &CwtchPeerHandler{Onion: rai.RemoteHostname, Peer: cp}
|
||||||
|
@ -318,7 +336,7 @@ func (cp *cwtchPeer) Listen() error {
|
||||||
if cp.dataHandler != nil {
|
if cp.dataHandler != nil {
|
||||||
af.AddHandler("im.cwtch.peer.data", func(rai *application.ApplicationInstance) func() channels.Handler {
|
af.AddHandler("im.cwtch.peer.data", func(rai *application.ApplicationInstance) func() channels.Handler {
|
||||||
cpi := new(CwtchPeerInstance)
|
cpi := new(CwtchPeerInstance)
|
||||||
cpi.Init(rai, cwtchpeer)
|
cpi.Init(rai, ra)
|
||||||
return func() channels.Handler {
|
return func() channels.Handler {
|
||||||
cpc := new(peer.CwtchPeerDataChannel)
|
cpc := new(peer.CwtchPeerDataChannel)
|
||||||
cpc.Handler = &CwtchPeerHandler{Onion: rai.RemoteHostname, Peer: cp, DataHandler: cp.dataHandler}
|
cpc.Handler = &CwtchPeerHandler{Onion: rai.RemoteHostname, Peer: cp, DataHandler: cp.dataHandler}
|
||||||
|
@ -332,15 +350,16 @@ func (cp *cwtchPeer) Listen() error {
|
||||||
af.AddHandler(handlers[i], cp.aif.GetHandler(handlers[i]))
|
af.AddHandler(handlers[i], cp.aif.GetHandler(handlers[i]))
|
||||||
}
|
}
|
||||||
|
|
||||||
cwtchpeer.InitV3(cp.Profile.Name, identity.InitializeV3(cp.Profile.Name, &cp.Profile.Ed25519PrivateKey, &cp.Profile.Ed25519PublicKey), af, cp)
|
ra.Init(cp.mn, cp.Profile.Name, identity.InitializeV3(cp.Profile.Name, &cp.Profile.Ed25519PrivateKey, &cp.Profile.Ed25519PublicKey), af, cp)
|
||||||
log.Printf("Running cwtch peer on %v", l.Addr().String())
|
log.Printf("Running cwtch peer on %v", onionService.AddressFull())
|
||||||
cp.app = cwtchpeer
|
cp.app = ra
|
||||||
cwtchpeer.Run(l)
|
ra.Run(onionService)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown kills all connections and cleans up all goroutines for the peer
|
// Shutdown kills all connections and cleans up all goroutines for the peer
|
||||||
func (cp *cwtchPeer) Shutdown() {
|
func (cp *cwtchPeer) Shutdown() {
|
||||||
|
cp.shutdown = true
|
||||||
cp.connectionsManager.Shutdown()
|
cp.connectionsManager.Shutdown()
|
||||||
if cp.app != nil {
|
if cp.app != nil {
|
||||||
cp.app.Shutdown()
|
cp.app.Shutdown()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package peer
|
package peer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,7 +22,9 @@ func TestCwtchPeerGenerate(t *testing.T) {
|
||||||
func TestTrustPeer(t *testing.T) {
|
func TestTrustPeer(t *testing.T) {
|
||||||
groupName := "test.server"
|
groupName := "test.server"
|
||||||
alice := NewCwtchPeer("alice")
|
alice := NewCwtchPeer("alice")
|
||||||
|
alice.Init(connectivity.LocalProvider())
|
||||||
bob := NewCwtchPeer("bob")
|
bob := NewCwtchPeer("bob")
|
||||||
|
bob.Init(connectivity.LocalProvider())
|
||||||
|
|
||||||
bobOnion := bob.GetProfile().Onion
|
bobOnion := bob.GetProfile().Onion
|
||||||
aliceOnion := alice.GetProfile().Onion
|
aliceOnion := alice.GetProfile().Onion
|
||||||
|
|
|
@ -2,8 +2,10 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
cwtchserver "cwtch.im/cwtch/server"
|
cwtchserver "cwtch.im/cwtch/server"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -15,9 +17,16 @@ func main() {
|
||||||
|
|
||||||
serverConfig := cwtchserver.LoadConfig(configDir, serverConfigFile)
|
serverConfig := cwtchserver.LoadConfig(configDir, serverConfigFile)
|
||||||
|
|
||||||
|
mn, err := connectivity.StartTor(path.Join(configDir, "tor"), "")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("\nError connecting to Tor: %v\n", err)
|
||||||
|
}
|
||||||
|
defer mn.Close()
|
||||||
|
|
||||||
server := new(cwtchserver.Server)
|
server := new(cwtchserver.Server)
|
||||||
log.Printf("starting cwtch server...")
|
log.Printf("starting cwtch server...")
|
||||||
|
|
||||||
// TODO load params from .cwtch/server.conf or command line flag
|
// TODO load params from .cwtch/server.conf or command line flag
|
||||||
server.Run(serverConfig)
|
// TODO: respond to HUP so t.Close is gracefully called
|
||||||
|
server.Run(mn, serverConfig)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"cwtch.im/cwtch/storage"
|
"cwtch.im/cwtch/storage"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
"git.openprivacy.ca/openprivacy/libricochet-go/application"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
|
||||||
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,12 +21,14 @@ type Server struct {
|
||||||
|
|
||||||
// Run starts a server with the given privateKey
|
// Run starts a server with the given privateKey
|
||||||
// TODO: surface errors
|
// TODO: surface errors
|
||||||
func (s *Server) Run(serverConfig Config) {
|
// TODO: handle HUP/KILL signals to exit and close Tor gracefully
|
||||||
|
// TODO: handle user input to exit
|
||||||
|
func (s *Server) Run(mn connectivity.Mixnet, serverConfig Config) {
|
||||||
s.config = serverConfig
|
s.config = serverConfig
|
||||||
cwtchserver := new(application.RicochetApplication)
|
cwtchserver := new(application.RicochetApplication)
|
||||||
s.metricsPack.Start(cwtchserver, serverConfig.ConfigDir, s.config.ServerReporting.LogMetricsToFile)
|
s.metricsPack.Start(cwtchserver, serverConfig.ConfigDir, s.config.ServerReporting.LogMetricsToFile)
|
||||||
|
|
||||||
l, err := application.SetupOnionV3("127.0.0.1:9051", "tcp4", "", s.config.PrivateKey, utils.GetTorV3Hostname(s.config.PublicKey), 9878)
|
listenService, err := mn.Listen(s.config.PrivateKey, application.RicochetPort)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error setting up onion service: %v", err)
|
log.Fatalf("error setting up onion service: %v", err)
|
||||||
|
@ -66,10 +68,10 @@ func (s *Server) Run(serverConfig Config) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
cwtchserver.InitV3("cwtch server for "+l.Addr().String(), s.config.Identity(), af, new(application.AcceptAllContactManager))
|
cwtchserver.Init(mn, "cwtch server for "+listenService.AddressIdentity(), s.config.Identity(), af, new(application.AcceptAllContactManager))
|
||||||
log.Printf("cwtch server running on cwtch:%s", l.Addr().String())
|
log.Printf("cwtch server running on cwtch:%s", listenService.AddressFull())
|
||||||
s.app = cwtchserver
|
s.app = cwtchserver
|
||||||
s.app.Run(l)
|
s.app.Run(listenService)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown kills the app closing all connections and freeing all goroutines
|
// Shutdown kills the app closing all connections and freeing all goroutines
|
||||||
|
|
|
@ -6,9 +6,11 @@ import (
|
||||||
"cwtch.im/cwtch/peer/connections"
|
"cwtch.im/cwtch/peer/connections"
|
||||||
cwtchserver "cwtch.im/cwtch/server"
|
cwtchserver "cwtch.im/cwtch/server"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -52,7 +54,7 @@ func serverCheck(t *testing.T, serverAddr string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForPeerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
|
func waitForPeerServerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
|
||||||
for {
|
for {
|
||||||
servers := peer.GetServers()
|
servers := peer.GetServers()
|
||||||
state, ok := servers[server]
|
state, ok := servers[server]
|
||||||
|
@ -61,6 +63,7 @@ func waitForPeerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
|
||||||
t.Fatalf("%v could not connect to %v", peer.GetProfile().Onion, server)
|
t.Fatalf("%v could not connect to %v", peer.GetProfile().Onion, server)
|
||||||
}
|
}
|
||||||
if state != connections.AUTHENTICATED {
|
if state != connections.AUTHENTICATED {
|
||||||
|
fmt.Printf("peer %v waiting connect to server %v, currently: %v\n", peer.GetProfile().Onion, server, connections.ConnectionStateName[state])
|
||||||
time.Sleep(time.Second * 10)
|
time.Sleep(time.Second * 10)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -72,11 +75,37 @@ func waitForPeerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func waitForPeerPeerConnection(t *testing.T, peera peer.CwtchPeer, peerb peer.CwtchPeer) {
|
||||||
|
for {
|
||||||
|
peers := peera.GetPeers()
|
||||||
|
state, ok := peers[peerb.GetProfile().Onion]
|
||||||
|
if ok {
|
||||||
|
if state == connections.FAILED {
|
||||||
|
t.Fatalf("%v could not connect to %v", peera.GetProfile().Onion, peerb.GetProfile().Onion)
|
||||||
|
}
|
||||||
|
if state != connections.AUTHENTICATED {
|
||||||
|
fmt.Printf("peer% v waiting connect to peer %v, currently: %v\n", peera.GetProfile().Onion, peerb.GetProfile().Onion, connections.ConnectionStateName[state])
|
||||||
|
time.Sleep(time.Second * 10)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatalf("peer peer connectiond %v should have entry for server %v", peers, peerb.GetProfile().Onion)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func TestCwtchPeerIntegration(t *testing.T) {
|
func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
// Hide logging "noise"
|
// Hide logging "noise"
|
||||||
log.SetOutput(ioutil.Discard)
|
log.SetOutput(ioutil.Discard)
|
||||||
numGoRoutinesStart := runtime.NumGoroutine()
|
numGoRoutinesStart := runtime.NumGoroutine()
|
||||||
|
|
||||||
|
mn, err := connectivity.StartTor(".", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Could not start Tor: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// ***** Cwtch Server managment *****
|
// ***** Cwtch Server managment *****
|
||||||
var server *cwtchserver.Server
|
var server *cwtchserver.Server
|
||||||
|
|
||||||
|
@ -88,10 +117,11 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
fmt.Println("No server found!")
|
fmt.Println("No server found!")
|
||||||
server = new(cwtchserver.Server)
|
server = new(cwtchserver.Server)
|
||||||
fmt.Println("Starting cwtch server...")
|
fmt.Println("Starting cwtch server...")
|
||||||
|
os.Remove("server-test.json")
|
||||||
config := cwtchserver.LoadConfig(".", "server-test.json")
|
config := cwtchserver.LoadConfig(".", "server-test.json")
|
||||||
identity := config.Identity()
|
identity := config.Identity()
|
||||||
serverAddr = identity.Hostname()
|
serverAddr = identity.Hostname()
|
||||||
go server.Run(config)
|
go server.Run(mn, config)
|
||||||
|
|
||||||
// let tor get established
|
// let tor get established
|
||||||
fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr)
|
fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr)
|
||||||
|
@ -105,17 +135,20 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
|
|
||||||
fmt.Println("Creating Alice...")
|
fmt.Println("Creating Alice...")
|
||||||
alice := peer.NewCwtchPeer("Alice")
|
alice := peer.NewCwtchPeer("Alice")
|
||||||
go alice.Listen()
|
alice.Init(mn)
|
||||||
|
alice.Listen()
|
||||||
fmt.Println("Alice created:", alice.GetProfile().Onion)
|
fmt.Println("Alice created:", alice.GetProfile().Onion)
|
||||||
|
|
||||||
fmt.Println("Creating Bob...")
|
fmt.Println("Creating Bob...")
|
||||||
bob := peer.NewCwtchPeer("Bob")
|
bob := peer.NewCwtchPeer("Bob")
|
||||||
go bob.Listen()
|
bob.Init(mn)
|
||||||
|
bob.Listen()
|
||||||
fmt.Println("Bob created:", bob.GetProfile().Onion)
|
fmt.Println("Bob created:", bob.GetProfile().Onion)
|
||||||
|
|
||||||
fmt.Println("Creating Carol...")
|
fmt.Println("Creating Carol...")
|
||||||
carol := peer.NewCwtchPeer("Carol")
|
carol := peer.NewCwtchPeer("Carol")
|
||||||
go carol.Listen()
|
carol.Init(mn)
|
||||||
|
carol.Listen()
|
||||||
fmt.Println("Carol created:", carol.GetProfile().Onion)
|
fmt.Println("Carol created:", carol.GetProfile().Onion)
|
||||||
|
|
||||||
fmt.Println("Waiting for Alice, Bob, and Carol to connection with onion network...")
|
fmt.Println("Waiting for Alice, Bob, and Carol to connection with onion network...")
|
||||||
|
@ -142,8 +175,17 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
fmt.Println("Bob joining server...")
|
fmt.Println("Bob joining server...")
|
||||||
bob.JoinServer(serverAddr)
|
bob.JoinServer(serverAddr)
|
||||||
|
|
||||||
fmt.Println("Waiting for peerings and server joins...")
|
fmt.Println("Waiting for alice to join server...")
|
||||||
time.Sleep(time.Second * 240)
|
waitForPeerServerConnection(t, alice, serverAddr)
|
||||||
|
|
||||||
|
fmt.Println("Waiting for bob to join server...")
|
||||||
|
waitForPeerServerConnection(t, bob, serverAddr)
|
||||||
|
|
||||||
|
fmt.Println("Waiting for alice and Bob to peer...")
|
||||||
|
waitForPeerPeerConnection(t, alice, bob)
|
||||||
|
|
||||||
|
/*fmt.Println("Waiting for peerings and server joins...")
|
||||||
|
time.Sleep(time.Second * 240)*/
|
||||||
|
|
||||||
fmt.Println("Alice inviting Bob to group...")
|
fmt.Println("Alice inviting Bob to group...")
|
||||||
err = alice.InviteOnionToGroup(bob.GetProfile().Onion, groupID)
|
err = alice.InviteOnionToGroup(bob.GetProfile().Onion, groupID)
|
||||||
|
@ -193,8 +235,8 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
time.Sleep(time.Second * 110)
|
time.Sleep(time.Second * 110)
|
||||||
*/
|
*/
|
||||||
// Wait for them to join the server
|
// Wait for them to join the server
|
||||||
waitForPeerConnection(t, alice, serverAddr)
|
waitForPeerServerConnection(t, alice, serverAddr)
|
||||||
waitForPeerConnection(t, bob, serverAddr)
|
waitForPeerServerConnection(t, bob, serverAddr)
|
||||||
//numGouRoutinesPostServerConnect := runtime.NumGoroutine()
|
//numGouRoutinesPostServerConnect := runtime.NumGoroutine()
|
||||||
|
|
||||||
// ***** Conversation *****
|
// ***** Conversation *****
|
||||||
|
@ -246,7 +288,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
|
|
||||||
fmt.Println("Carol joining server...")
|
fmt.Println("Carol joining server...")
|
||||||
carol.JoinServer(serverAddr)
|
carol.JoinServer(serverAddr)
|
||||||
waitForPeerConnection(t, carol, serverAddr)
|
waitForPeerServerConnection(t, carol, serverAddr)
|
||||||
numGoRotinesPostCarolConnect := runtime.NumGoroutine()
|
numGoRotinesPostCarolConnect := runtime.NumGoroutine()
|
||||||
|
|
||||||
fmt.Println("Bob> ", bobLines[2])
|
fmt.Println("Bob> ", bobLines[2])
|
||||||
|
|
|
@ -16,7 +16,6 @@ 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.send.cover.out -v ./server/send
|
||||||
go test ${1} -coverprofile=server.metrics.cover.out -v ./server/metrics
|
go test ${1} -coverprofile=server.metrics.cover.out -v ./server/metrics
|
||||||
go test ${1} -coverprofile=server.cover.out -v ./server
|
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 | \
|
echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \
|
||||||
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out
|
awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out
|
||||||
rm -rf *.cover.out
|
rm -rf *.cover.out
|
||||||
|
|
Loading…
Reference in New Issue