16
20
Fork 16

Following libricochetgo's migration to bine and a generic Mixnet

interface.
Dieser Commit ist enthalten in:
Dan Ballard 2018-11-10 14:14:12 -08:00
Ursprung 07ffd780b0
Commit 85a2c44891
16 geänderte Dateien mit 163 neuen und 309 gelöschten Zeilen

Datei anzeigen

@ -2,12 +2,12 @@ package app
import (
"crypto/rand"
"cwtch.im/cwtch/connectivity/tor"
"cwtch.im/cwtch/peer"
"cwtch.im/cwtch/storage"
"encoding/hex"
"fmt"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"io/ioutil"
"log"
"os"
@ -18,7 +18,7 @@ import (
type application struct {
peers map[string]peer.CwtchPeer
torManager *tor.Manager
mn connectivity.Mixnet
directory string
mutex sync.Mutex
primaryonion string
@ -35,23 +35,17 @@ type Application interface {
GetPeer(onion string) peer.CwtchPeer
ListPeers() map[string]string
GetTorStatus() (map[string]string, error)
//GetTorStatus() (map[string]string, error)
Shutdown()
}
// 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{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory}
os.MkdirAll(path.Join(appDirectory, "tor"), 0700)
func NewApp(mn connectivity.Mixnet, appDirectory string) Application {
log.Printf("NewApp(%v)\n", appDirectory)
app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory, mn: mn}
os.Mkdir(path.Join(app.directory, "profiles"), 0700)
err := app.startTor(torPath)
if err != nil {
return nil, err
}
return app, nil
return app
}
func generateRandomFilename() string {
@ -78,7 +72,8 @@ func (app *application) CreatePeer(name string, password string) (peer.CwtchPeer
if err != nil {
return nil, err
}
app.startPeer(p)
p.Init(app.mn)
p.Listen()
_, exists := app.peers[p.GetProfile().Onion]
if exists {
p.Shutdown()
@ -104,7 +99,6 @@ func (app *application) LoadProfiles(password string) error {
p, err := fileStore.Load()
if err != nil {
continue
}
@ -114,7 +108,8 @@ func (app *application) LoadProfiles(password string) error {
log.Printf("Error: profile for onion %v already exists", p.GetProfile().Onion)
continue
}
app.startPeer(p)
p.Init(app.mn)
p.Listen()
app.mutex.Lock()
app.peers[p.GetProfile().Onion] = p
app.storage[p.GetProfile().Onion] = fileStore
@ -126,40 +121,6 @@ func (app *application) LoadProfiles(password string) error {
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
func (app *application) ListPeers() map[string]string {
keys := map[string]string{}
@ -182,15 +143,15 @@ func (app *application) GetPeer(onion string) peer.CwtchPeer {
return nil
}
/*
// GetTorStatus returns tor control port bootstrap-phase status info in a map
func (app *application) GetTorStatus() (map[string]string, error) {
return app.torManager.GetStatus()
}
}*/
// Shutdown shutsdown all peers of an app and then the tormanager
func (app *application) Shutdown() {
for _, peer := range app.peers {
peer.Shutdown()
}
app.torManager.Shutdown()
}

Datei anzeigen

@ -8,11 +8,11 @@ import (
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/peer/connections"
"fmt"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"github.com/c-bata/go-prompt"
"golang.org/x/crypto/ssh/terminal"
"log"
"os"
"os/exec"
"os/user"
"path"
"strings"
@ -250,17 +250,16 @@ func main() {
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()
if err != nil {
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 {
log.Fatalf("Error initializing application: %v", err)
}
@ -307,6 +306,12 @@ func main() {
quit = true
case "/new-profile":
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")
password := ""
@ -329,17 +334,17 @@ func main() {
}
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 {
p, err := app.CreatePeer(commands[1], password)
p, err := app.CreatePeer(name, password)
if err == nil {
stopGroupFollow()
fmt.Printf("\nNew profile created for %v\n", commands[1])
fmt.Printf("\nNew profile created for %v\n", name)
peer = p
suggestions = append(suggestionsBase, suggestionsSelectedProfile...)
} 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 {
@ -597,6 +602,6 @@ func main() {
}
app.Shutdown()
mn.Close()
os.Exit(0)
}

Datei anzeigen

@ -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
}

Datei anzeigen

@ -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()
}

Datei anzeigen

@ -4,6 +4,7 @@ import (
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/protocol"
"git.openprivacy.ca/openprivacy/libricochet-go/application"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"sync"
"time"
)
@ -14,11 +15,13 @@ type Manager struct {
serverConnections map[string]*PeerServerConnection
lock sync.Mutex
breakChannel chan bool
mn connectivity.Mixnet
}
// NewConnectionsManager creates a new instance of Manager.
func NewConnectionsManager() *Manager {
func NewConnectionsManager(mn connectivity.Mixnet) *Manager {
m := new(Manager)
m.mn = mn
m.peerConnections = make(map[string]*PeerPeerConnection)
m.serverConnections = make(map[string]*PeerServerConnection)
m.breakChannel = make(chan bool)
@ -32,7 +35,7 @@ func (m *Manager) ManagePeerConnection(host string, profile *model.Profile, data
_, exists := m.peerConnections[host]
if !exists {
ppc := NewPeerPeerConnection(host, profile, dataHandler, aif)
ppc := NewPeerPeerConnection(m.mn, host, profile, dataHandler, aif)
go ppc.Run()
m.peerConnections[host] = ppc
return ppc
@ -46,7 +49,7 @@ func (m *Manager) ManageServerConnection(host string, handler func(string, *prot
_, exists := m.serverConnections[host]
if !exists {
psc := NewPeerServerConnection(host)
psc := NewPeerServerConnection(m.mn, host)
go psc.Run()
psc.GroupMessageHandler = handler
m.serverConnections[host] = psc

Datei anzeigen

@ -1,10 +1,11 @@
package connections
import (
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"testing"
)
func TestConnectionsManager(t *testing.T) {
// TODO We need to encapsulate connections behind a well defined interface for tesintg
NewConnectionsManager()
NewConnectionsManager(connectivity.LocalProvider())
}

Datei anzeigen

@ -8,6 +8,7 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go/application"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"log"
"time"
@ -22,11 +23,13 @@ type PeerPeerConnection struct {
profile *model.Profile
dataHandler func(string, []byte) []byte
aif application.ApplicationInstanceFactory
mn connectivity.Mixnet
}
// 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.mn = mn
ppc.PeerHostname = peerhostname
ppc.profile = profile
ppc.dataHandler = dataHandler
@ -107,7 +110,7 @@ func (ppc *PeerPeerConnection) WaitTilAuthenticated() {
// Run manages the setup and teardown of a peer->peer connection
func (ppc *PeerPeerConnection) Run() error {
ppc.state = CONNECTING
rc, err := goricochet.Open(ppc.PeerHostname)
rc, err := goricochet.Open(ppc.mn, ppc.PeerHostname)
if err == nil {
rc.TraceLog(false)
ppc.connection = rc

Datei anzeigen

@ -5,10 +5,12 @@ import (
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/peer/peer"
"cwtch.im/cwtch/protocol"
"fmt"
"git.openprivacy.ca/openprivacy/libricochet-go"
"git.openprivacy.ca/openprivacy/libricochet-go/application"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"golang.org/x/crypto/ed25519"
"net"
@ -59,13 +61,14 @@ func TestPeerPeerConnection(t *testing.T) {
profile := model.GenerateNewProfile("alice")
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.Init()
go runtestpeer(t, tp, identity)
state := ppc.GetState()
if state != DISCONNECTED {
fmt.Println("ERROR state should be disconnected")
t.Errorf("new connections should start in disconnected state")
}
go ppc.Run()
@ -80,5 +83,4 @@ func TestPeerPeerConnection(t *testing.T) {
if tp.ReceivedGroupInvite == false {
t.Errorf("should have received an group invite packet")
}
}

Datei anzeigen

@ -10,6 +10,7 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"golang.org/x/crypto/ed25519"
"log"
@ -22,13 +23,15 @@ type PeerServerConnection struct {
Server string
state ConnectionState
connection *connection.Connection
mn connectivity.Mixnet
GroupMessageHandler func(string, *protocol.GroupMessage)
}
// 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.mn = mn
psc.Server = serverhostname
psc.Init()
return psc
@ -52,7 +55,7 @@ func (psc *PeerServerConnection) WaitTilAuthenticated() {
// Run manages the setup and teardown of a peer server connection
func (psc *PeerServerConnection) Run() error {
log.Printf("Connecting to %v", psc.Server)
rc, err := goricochet.Open(psc.Server)
rc, err := goricochet.Open(psc.mn, psc.Server)
if err == nil {
rc.TraceLog(true)
psc.connection = rc

Datei anzeigen

@ -8,6 +8,7 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"git.openprivacy.ca/openprivacy/libricochet-go/connection"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/identity"
"golang.org/x/crypto/ed25519"
"net"
@ -72,7 +73,7 @@ func TestPeerServerConnection(t *testing.T) {
go runtestserver(t, ts, identity)
onionAddr := identity.Hostname()
psc := NewPeerServerConnection("127.0.0.1:5451|" + onionAddr)
psc := NewPeerServerConnection(connectivity.LocalProvider(), "127.0.0.1:5451|"+onionAddr)
numcalls := 0
psc.GroupMessageHandler = func(s string, gm *protocol.GroupMessage) {
numcalls++

Datei anzeigen

@ -12,6 +12,7 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go/application"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"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/utils"
"github.com/golang/protobuf/proto"
@ -19,6 +20,7 @@ import (
"log"
"strings"
"sync"
"time"
)
// cwtchPeer manages incoming and outgoing connections and all processing for a Cwtch cwtchPeer
@ -26,17 +28,19 @@ type cwtchPeer struct {
connection.AutoConnectionHandler
Profile *model.Profile
app *application.RicochetApplication
mn connectivity.Mixnet
mutex sync.Mutex
connectionsManager *connections.Manager
dataHandler func(string, []byte) []byte
//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
// directly implement a cwtchPeer.
type CwtchPeer interface {
Init()
Init(connectivity.Mixnet)
PeerWithOnion(string) *connections.PeerPeerConnection
InviteOnionToGroup(string, string) error
@ -66,7 +70,7 @@ type CwtchPeer interface {
SetApplicationInstanceFactory(factory application.ApplicationInstanceFactory)
SetPeerDataHandler(func(string, []byte) []byte)
Listen() error
Listen()
Shutdown()
}
@ -74,7 +78,7 @@ type CwtchPeer interface {
func NewCwtchPeer(name string) CwtchPeer {
cp := new(cwtchPeer)
cp.Profile = model.GenerateNewProfile(name)
cp.Init()
cp.shutdown = false
return cp
}
@ -82,13 +86,13 @@ func NewCwtchPeer(name string) CwtchPeer {
func FromProfile(profile *model.Profile) CwtchPeer {
cp := new(cwtchPeer)
cp.Profile = profile
cp.Init()
return cp
}
// Init instantiates a cwtchPeer
func (cp *cwtchPeer) Init() {
cp.connectionsManager = connections.NewConnectionsManager()
func (cp *cwtchPeer) Init(mn connectivity.Mixnet) {
cp.mn = mn
cp.connectionsManager = connections.NewConnectionsManager(cp.mn)
go cp.connectionsManager.AttemptReconnections()
}
@ -295,11 +299,25 @@ func (cp *cwtchPeer) ContactRequest(name string, message string) string {
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
func (cp *cwtchPeer) Listen() error {
cwtchpeer := new(application.RicochetApplication)
l, err := application.SetupOnionV3("127.0.0.1:9051", "tcp4", "", cp.Profile.Ed25519PrivateKey, cp.GetProfile().Onion, 9878)
if err != nil && fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision" {
func (cp *cwtchPeer) listenFn() error {
ra := new(application.RicochetApplication)
onionService, err := cp.mn.Listen(cp.Profile.Ed25519PrivateKey, application.RicochetPort)
if err != nil /*&& fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision"*/ {
return err
}
@ -307,7 +325,7 @@ func (cp *cwtchPeer) Listen() error {
af.Init()
af.AddHandler("im.cwtch.peer", func(rai *application.ApplicationInstance) func() channels.Handler {
cpi := new(CwtchPeerInstance)
cpi.Init(rai, cwtchpeer)
cpi.Init(rai, ra)
return func() channels.Handler {
cpc := new(peer.CwtchPeerChannel)
cpc.Handler = &CwtchPeerHandler{Onion: rai.RemoteHostname, Peer: cp}
@ -318,7 +336,7 @@ func (cp *cwtchPeer) Listen() error {
if cp.dataHandler != nil {
af.AddHandler("im.cwtch.peer.data", func(rai *application.ApplicationInstance) func() channels.Handler {
cpi := new(CwtchPeerInstance)
cpi.Init(rai, cwtchpeer)
cpi.Init(rai, ra)
return func() channels.Handler {
cpc := new(peer.CwtchPeerDataChannel)
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]))
}
cwtchpeer.InitV3(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())
cp.app = cwtchpeer
cwtchpeer.Run(l)
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", onionService.AddressFull())
cp.app = ra
ra.Run(onionService)
return nil
}
// Shutdown kills all connections and cleans up all goroutines for the peer
func (cp *cwtchPeer) Shutdown() {
cp.shutdown = true
cp.connectionsManager.Shutdown()
if cp.app != nil {
cp.app.Shutdown()

Datei anzeigen

@ -1,6 +1,7 @@
package peer
import (
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"testing"
)
@ -21,7 +22,9 @@ func TestCwtchPeerGenerate(t *testing.T) {
func TestTrustPeer(t *testing.T) {
groupName := "test.server"
alice := NewCwtchPeer("alice")
alice.Init(connectivity.LocalProvider())
bob := NewCwtchPeer("bob")
bob.Init(connectivity.LocalProvider())
bobOnion := bob.GetProfile().Onion
aliceOnion := alice.GetProfile().Onion

Datei anzeigen

@ -2,8 +2,10 @@ package main
import (
cwtchserver "cwtch.im/cwtch/server"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"log"
"os"
"path"
)
const (
@ -15,9 +17,16 @@ func main() {
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)
log.Printf("starting cwtch server...")
// 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)
}

Datei anzeigen

@ -8,7 +8,7 @@ import (
"cwtch.im/cwtch/storage"
"git.openprivacy.ca/openprivacy/libricochet-go/application"
"git.openprivacy.ca/openprivacy/libricochet-go/channels"
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"log"
)
@ -21,12 +21,14 @@ type Server struct {
// Run starts a server with the given privateKey
// 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
cwtchserver := new(application.RicochetApplication)
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 {
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))
log.Printf("cwtch server running on cwtch:%s", l.Addr().String())
cwtchserver.Init(mn, "cwtch server for "+listenService.AddressIdentity(), s.config.Identity(), af, new(application.AcceptAllContactManager))
log.Printf("cwtch server running on cwtch:%s", listenService.AddressFull())
s.app = cwtchserver
s.app.Run(l)
s.app.Run(listenService)
}
// Shutdown kills the app closing all connections and freeing all goroutines

Datei anzeigen

@ -6,9 +6,11 @@ import (
"cwtch.im/cwtch/peer/connections"
cwtchserver "cwtch.im/cwtch/server"
"fmt"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"golang.org/x/net/proxy"
"io/ioutil"
"log"
"os"
"runtime"
"testing"
"time"
@ -52,7 +54,7 @@ func serverCheck(t *testing.T, serverAddr string) bool {
return true
}
func waitForPeerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
func waitForPeerServerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
for {
servers := peer.GetServers()
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)
}
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)
continue
}
@ -72,11 +75,37 @@ func waitForPeerConnection(t *testing.T, peer peer.CwtchPeer, server string) {
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) {
// Hide logging "noise"
log.SetOutput(ioutil.Discard)
numGoRoutinesStart := runtime.NumGoroutine()
mn, err := connectivity.StartTor(".", "")
if err != nil {
t.Fatalf("Could not start Tor: %v", err)
}
// ***** Cwtch Server managment *****
var server *cwtchserver.Server
@ -88,10 +117,11 @@ func TestCwtchPeerIntegration(t *testing.T) {
fmt.Println("No server found!")
server = new(cwtchserver.Server)
fmt.Println("Starting cwtch server...")
os.Remove("server-test.json")
config := cwtchserver.LoadConfig(".", "server-test.json")
identity := config.Identity()
serverAddr = identity.Hostname()
go server.Run(config)
go server.Run(mn, config)
// let tor get established
fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr)
@ -105,17 +135,20 @@ func TestCwtchPeerIntegration(t *testing.T) {
fmt.Println("Creating Alice...")
alice := peer.NewCwtchPeer("Alice")
go alice.Listen()
alice.Init(mn)
alice.Listen()
fmt.Println("Alice created:", alice.GetProfile().Onion)
fmt.Println("Creating Bob...")
bob := peer.NewCwtchPeer("Bob")
go bob.Listen()
bob.Init(mn)
bob.Listen()
fmt.Println("Bob created:", bob.GetProfile().Onion)
fmt.Println("Creating Carol...")
carol := peer.NewCwtchPeer("Carol")
go carol.Listen()
carol.Init(mn)
carol.Listen()
fmt.Println("Carol created:", carol.GetProfile().Onion)
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...")
bob.JoinServer(serverAddr)
fmt.Println("Waiting for peerings and server joins...")
time.Sleep(time.Second * 240)
fmt.Println("Waiting for alice to join server...")
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...")
err = alice.InviteOnionToGroup(bob.GetProfile().Onion, groupID)
@ -193,8 +235,8 @@ func TestCwtchPeerIntegration(t *testing.T) {
time.Sleep(time.Second * 110)
*/
// Wait for them to join the server
waitForPeerConnection(t, alice, serverAddr)
waitForPeerConnection(t, bob, serverAddr)
waitForPeerServerConnection(t, alice, serverAddr)
waitForPeerServerConnection(t, bob, serverAddr)
//numGouRoutinesPostServerConnect := runtime.NumGoroutine()
// ***** Conversation *****
@ -246,7 +288,7 @@ func TestCwtchPeerIntegration(t *testing.T) {
fmt.Println("Carol joining server...")
carol.JoinServer(serverAddr)
waitForPeerConnection(t, carol, serverAddr)
waitForPeerServerConnection(t, carol, serverAddr)
numGoRotinesPostCarolConnect := runtime.NumGoroutine()
fmt.Println("Bob> ", bobLines[2])

Datei anzeigen

@ -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.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