218 lines
7.3 KiB
Go
218 lines
7.3 KiB
Go
package testing
|
|
|
|
import (
|
|
"crypto/rand"
|
|
app2 "cwtch.im/cwtch/app"
|
|
"cwtch.im/cwtch/event"
|
|
"cwtch.im/cwtch/functionality/hybrid"
|
|
"cwtch.im/cwtch/model/constants"
|
|
"cwtch.im/cwtch/peer"
|
|
"cwtch.im/cwtch/protocol/connections"
|
|
"encoding/base64"
|
|
"fmt"
|
|
"git.openprivacy.ca/openprivacy/connectivity/tor"
|
|
"git.openprivacy.ca/openprivacy/log"
|
|
_ "github.com/mutecomm/go-sqlcipher/v4"
|
|
mrand "math/rand"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"runtime/pprof"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestHyrbidGroupIntegration(t *testing.T) {
|
|
|
|
os.RemoveAll("./storage")
|
|
os.RemoveAll("./managerstorage")
|
|
|
|
// Goroutine Monitoring Start..
|
|
numGoRoutinesStart := runtime.NumGoroutine()
|
|
|
|
log.AddEverythingFromPattern("connectivity")
|
|
log.SetLevel(log.LevelInfo)
|
|
log.ExcludeFromPattern("connection/connection")
|
|
log.ExcludeFromPattern("outbound/3dhauthchannel")
|
|
log.ExcludeFromPattern("event/eventmanager")
|
|
log.ExcludeFromPattern("tapir")
|
|
|
|
os.Mkdir("tordir", 0700)
|
|
dataDir := path.Join("tordir", "tor")
|
|
os.MkdirAll(dataDir, 0700)
|
|
|
|
// we don't need real randomness for the port, just to avoid a possible conflict...
|
|
socksPort := mrand.Intn(1000) + 9051
|
|
controlPort := mrand.Intn(1000) + 9052
|
|
|
|
// generate a random password
|
|
key := make([]byte, 64)
|
|
_, err := rand.Read(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
useCache := os.Getenv("TORCACHE") == "true"
|
|
|
|
torDataDir := ""
|
|
if useCache {
|
|
log.Infof("using tor cache")
|
|
torDataDir = filepath.Join(dataDir, "data-dir-torcache")
|
|
os.MkdirAll(torDataDir, 0700)
|
|
} else {
|
|
log.Infof("using clean tor data dir")
|
|
if torDataDir, err = os.MkdirTemp(dataDir, "data-dir-"); err != nil {
|
|
t.Fatalf("could not create data dir")
|
|
}
|
|
}
|
|
|
|
tor.NewTorrc().WithSocksPort(socksPort).WithOnionTrafficOnly().WithHashedPassword(base64.StdEncoding.EncodeToString(key)).WithControlPort(controlPort).Build("tordir/tor/torrc")
|
|
acn, err := tor.NewTorACNWithAuth("./tordir", path.Join("..", "tor"), torDataDir, controlPort, tor.HashedPasswordAuthenticator{Password: base64.StdEncoding.EncodeToString(key)})
|
|
if err != nil {
|
|
t.Fatalf("Could not start Tor: %v", err)
|
|
}
|
|
log.Infof("Waiting for tor to bootstrap...")
|
|
acn.WaitTillBootstrapped()
|
|
defer acn.Close()
|
|
|
|
// ***** Cwtch Server management *****
|
|
|
|
app := app2.NewApp(acn, "./storage", app2.LoadAppSettings("./storage"))
|
|
managerApp := app2.NewApp(acn, "./managerstorage", app2.LoadAppSettings("./managerstorage"))
|
|
|
|
// ***** cwtchPeer setup *****
|
|
// Turn on Groups Experiment...
|
|
settings := app.ReadSettings()
|
|
settings.ExperimentsEnabled = true
|
|
settings.Experiments[constants.GroupsExperiment] = true
|
|
settings.Experiments[constants.GroupManagerExperiment] = false
|
|
app.UpdateSettings(settings)
|
|
|
|
// Create a Manager App that has the Group Manager Experiment Enabled....
|
|
managerSettings := managerApp.ReadSettings()
|
|
managerSettings.ExperimentsEnabled = true
|
|
managerSettings.Experiments[constants.GroupsExperiment] = true
|
|
managerSettings.Experiments[constants.GroupManagerExperiment] = true
|
|
managerApp.UpdateSettings(managerSettings)
|
|
|
|
alice := MakeProfile(app, "Alice")
|
|
bob := MakeProfile(app, "Bob")
|
|
manager := MakeProfile(managerApp, "Manager")
|
|
|
|
waitTime := time.Duration(60) * time.Second
|
|
log.Infof("** Waiting for Alice, Bob, and Carol to register their onion hidden service on the network... (%v)\n", waitTime)
|
|
time.Sleep(waitTime)
|
|
log.Infof("** Wait Done!")
|
|
|
|
// Ok Lets Start By Creating a Hybrid Group...
|
|
|
|
hgmf := hybrid.GroupManagerFunctionality{}
|
|
ci, err := hgmf.ManageNewGroup(manager)
|
|
if err != nil {
|
|
t.Fatalf("could not create hybrid group: %v", err)
|
|
}
|
|
log.Infof("created a hybrid group: %d. moving onto adding hybrid contacts...", ci)
|
|
err = hgmf.AddHybridContact(manager, alice.GetOnion())
|
|
if err != nil {
|
|
t.Fatalf("could not create hybrid contact (alice): %v", err)
|
|
}
|
|
err = hgmf.AddHybridContact(manager, bob.GetOnion())
|
|
if err != nil {
|
|
t.Fatalf("could not create hybrid contact (bob): %v", err)
|
|
}
|
|
|
|
// Now we can allow alice, bob and carol to create a new hybrid group...
|
|
log.Infof("now we can allow alice bob and carol to join the hybrid group")
|
|
mgf := hybrid.ManagedGroupFunctionality{}
|
|
err = mgf.NewManagedGroup(alice, manager.GetOnion())
|
|
if err != nil {
|
|
t.Fatalf("could not create hybrid group contact (carol): %v", err)
|
|
}
|
|
alice.PeerWithOnion(manager.GetOnion()) // explictly trigger a peer request
|
|
err = mgf.NewManagedGroup(bob, manager.GetOnion())
|
|
if err != nil {
|
|
t.Fatalf("could not create hybrid group contact (carol): %v", err)
|
|
}
|
|
bob.PeerWithOnion(manager.GetOnion())
|
|
|
|
log.Infof("waiting for alice and manager to connect")
|
|
WaitForConnection(t, alice, manager.GetOnion(), connections.AUTHENTICATED)
|
|
log.Infof("waiting for bob and manager to connect")
|
|
WaitForConnection(t, bob, manager.GetOnion(), connections.AUTHENTICATED)
|
|
|
|
// at this pont we should be able to send messages to the group, and receive them in the timeline
|
|
log.Infof("sending message to group")
|
|
_, err = mgf.SendMessageToManagedGroup(alice, 1, "hello everyone!!!")
|
|
if err != nil {
|
|
t.Fatalf("hybrid group sending failed... %v", err)
|
|
}
|
|
|
|
time.Sleep(time.Second * 10)
|
|
|
|
bobMessages, err := bob.GetMostRecentMessages(1, 0, 0, 1)
|
|
if err != nil || len(bobMessages) != 1 {
|
|
t.Fatalf("hybrid group receipt failed... %v", err)
|
|
}
|
|
|
|
if bobMessages[0].Body != "hello everyone!!!" {
|
|
t.Fatalf("hybrid group receipt failed...message does not match")
|
|
}
|
|
|
|
aliceMessages, err := alice.GetMostRecentMessages(1, 0, 0, 1)
|
|
if err != nil || len(aliceMessages) != 1 {
|
|
t.Fatalf("hybrid group receipt failed... %v", err)
|
|
}
|
|
|
|
if aliceMessages[0].Attr[constants.AttrAck] != constants.True {
|
|
t.Fatalf("hybrid group receipt failed...alice's message was not ack'd")
|
|
}
|
|
|
|
// Time to Clean Up....
|
|
log.Infof("Shutting down Alice...")
|
|
app.ShutdownPeer(alice.GetOnion())
|
|
time.Sleep(time.Second * 3)
|
|
|
|
log.Infof("Shutting down Bob...")
|
|
app.ShutdownPeer(bob.GetOnion())
|
|
time.Sleep(time.Second * 3)
|
|
|
|
log.Infof("Shutting fown Manager...")
|
|
managerApp.ShutdownPeer(manager.GetOnion())
|
|
time.Sleep(time.Second * 3)
|
|
|
|
log.Infof("Shutting down apps...")
|
|
log.Infof("app Shutdown: %v\n", runtime.NumGoroutine())
|
|
app.Shutdown()
|
|
managerApp.Shutdown()
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
log.Infof("Done shutdown: %v\n", runtime.NumGoroutine())
|
|
|
|
log.Infof("Shutting down ACN...")
|
|
acn.Close()
|
|
time.Sleep(time.Second * 60) // the network status / heartbeat plugin might keep goroutines alive for a minute before killing them
|
|
|
|
numGoRoutinesPostAppShutdown := runtime.NumGoroutine()
|
|
|
|
// Printing out the current goroutines
|
|
// Very useful if we are leaking any.
|
|
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
|
|
fmt.Println("")
|
|
|
|
if numGoRoutinesStart != numGoRoutinesPostAppShutdown {
|
|
t.Errorf("Number of GoRoutines at start (%v) does not match number of goRoutines after cleanup of peers and servers (%v), clean up failed, v detected!", numGoRoutinesStart, numGoRoutinesPostAppShutdown)
|
|
}
|
|
}
|
|
|
|
func MakeProfile(application app2.Application, name string) peer.CwtchPeer {
|
|
application.CreateProfile(name, "asdfasdf", true)
|
|
p := app2.WaitGetPeer(application, name)
|
|
application.ConfigureConnections(p.GetOnion(), true, true, false)
|
|
log.Infof("%s created: %s", name, p.GetOnion())
|
|
// bob.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, "Bob") <- This is now done automatically by ProfileValueExtension, keeping this here for clarity
|
|
p.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite, event.NewRetValMessageFromPeer})
|
|
return p
|
|
}
|