2018-04-30 21:47:21 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2018-09-21 18:53:10 +00:00
|
|
|
"crypto/rand"
|
2019-01-04 21:44:21 +00:00
|
|
|
"cwtch.im/cwtch/event"
|
2018-05-28 18:05:06 +00:00
|
|
|
"cwtch.im/cwtch/peer"
|
2018-10-06 03:50:55 +00:00
|
|
|
"cwtch.im/cwtch/storage"
|
2018-09-21 18:53:10 +00:00
|
|
|
"encoding/hex"
|
2018-07-01 18:43:05 +00:00
|
|
|
"fmt"
|
2018-10-06 03:50:55 +00:00
|
|
|
|
2018-11-10 22:14:12 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
|
2018-12-04 02:52:11 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/libricochet-go/log"
|
2018-09-21 18:53:10 +00:00
|
|
|
"io/ioutil"
|
2018-07-01 18:43:05 +00:00
|
|
|
"os"
|
|
|
|
"path"
|
2018-09-21 18:53:10 +00:00
|
|
|
"path/filepath"
|
|
|
|
"sync"
|
2018-04-30 21:47:21 +00:00
|
|
|
)
|
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
type application struct {
|
2018-10-04 19:15:03 +00:00
|
|
|
peers map[string]peer.CwtchPeer
|
2018-11-22 18:01:04 +00:00
|
|
|
acn connectivity.ACN
|
2018-10-04 19:15:03 +00:00
|
|
|
directory string
|
|
|
|
mutex sync.Mutex
|
2018-10-04 04:35:30 +00:00
|
|
|
primaryonion string
|
2018-10-06 03:50:55 +00:00
|
|
|
storage map[string]storage.ProfileStore
|
2019-01-19 23:16:38 +00:00
|
|
|
eventBus *event.Manager
|
2018-09-21 18:53:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
|
|
|
|
type Application interface {
|
|
|
|
LoadProfiles(password string) error
|
|
|
|
CreatePeer(name string, password string) (peer.CwtchPeer, error)
|
|
|
|
|
2018-10-04 04:35:30 +00:00
|
|
|
PrimaryIdentity() peer.CwtchPeer
|
2018-09-21 18:53:10 +00:00
|
|
|
GetPeer(onion string) peer.CwtchPeer
|
|
|
|
ListPeers() map[string]string
|
2018-11-22 00:08:47 +00:00
|
|
|
LaunchPeers()
|
2018-09-21 18:53:10 +00:00
|
|
|
|
2019-01-19 23:16:38 +00:00
|
|
|
EventBus() *event.Manager
|
2018-10-05 23:27:57 +00:00
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
Shutdown()
|
2018-07-10 20:42:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
|
2018-11-22 18:01:04 +00:00
|
|
|
func NewApp(acn connectivity.ACN, appDirectory string) Application {
|
2018-12-04 02:52:11 +00:00
|
|
|
log.Debugf("NewApp(%v)\n", appDirectory)
|
2018-11-22 18:01:04 +00:00
|
|
|
app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory, acn: acn}
|
2018-09-21 18:53:10 +00:00
|
|
|
os.Mkdir(path.Join(app.directory, "profiles"), 0700)
|
2019-01-19 23:16:38 +00:00
|
|
|
app.eventBus = new(event.Manager)
|
|
|
|
app.eventBus.Initialize()
|
2018-11-10 22:14:12 +00:00
|
|
|
return app
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
func generateRandomFilename() string {
|
|
|
|
randBytes := make([]byte, 16)
|
|
|
|
rand.Read(randBytes)
|
|
|
|
return filepath.Join(hex.EncodeToString(randBytes))
|
|
|
|
}
|
|
|
|
|
2018-06-19 22:28:44 +00:00
|
|
|
// NewProfile creates a new cwtchPeer with a given name.
|
2018-09-21 18:53:10 +00:00
|
|
|
func (app *application) CreatePeer(name string, password string) (peer.CwtchPeer, error) {
|
2018-12-04 02:52:11 +00:00
|
|
|
log.Debugf("CreatePeer(%v)\n", name)
|
2018-09-21 18:53:10 +00:00
|
|
|
|
|
|
|
randomFileName := generateRandomFilename()
|
2019-01-21 20:11:40 +00:00
|
|
|
// TODO: eventBus per profile
|
|
|
|
profileStore, err := storage.NewProfileStore(app.eventBus, path.Join(app.directory, "profiles", randomFileName), password)
|
|
|
|
profileStore.Init(name)
|
2018-10-06 03:50:55 +00:00
|
|
|
p := peer.NewCwtchPeer(name)
|
2019-01-21 20:37:06 +00:00
|
|
|
app.eventBus.Publish(event.NewEvent(event.SetProfileName, map[event.Field]string{event.ProfileName: name}))
|
2018-09-27 00:08:54 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-01-19 23:16:38 +00:00
|
|
|
p.Init(app.acn, app.eventBus)
|
2018-09-21 18:53:10 +00:00
|
|
|
_, exists := app.peers[p.GetProfile().Onion]
|
|
|
|
if exists {
|
|
|
|
p.Shutdown()
|
|
|
|
return nil, fmt.Errorf("Error: profile for onion %v already exists", p.GetProfile().Onion)
|
2018-05-01 20:44:45 +00:00
|
|
|
}
|
2018-09-21 18:53:10 +00:00
|
|
|
app.mutex.Lock()
|
|
|
|
app.peers[p.GetProfile().Onion] = p
|
2019-01-21 20:11:40 +00:00
|
|
|
app.storage[p.GetProfile().Onion] = profileStore
|
2018-09-21 18:53:10 +00:00
|
|
|
app.mutex.Unlock()
|
|
|
|
|
|
|
|
return p, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (app *application) LoadProfiles(password string) error {
|
|
|
|
files, err := ioutil.ReadDir(path.Join(app.directory, "profiles"))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error: cannot read profiles directory: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
2018-10-06 03:50:55 +00:00
|
|
|
|
2019-01-21 20:11:40 +00:00
|
|
|
// TODO: Per profile eventBus
|
|
|
|
profileStore, err := storage.NewProfileStore(app.eventBus, path.Join(app.directory, "profiles", file.Name()), password)
|
2018-10-06 03:50:55 +00:00
|
|
|
|
2019-01-21 20:11:40 +00:00
|
|
|
err = profileStore.Load()
|
2018-09-21 18:53:10 +00:00
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2018-10-06 03:50:55 +00:00
|
|
|
|
2019-01-21 20:11:40 +00:00
|
|
|
profile := profileStore.GetProfileCopy()
|
|
|
|
_, exists := app.peers[profile.Onion]
|
2018-09-21 18:53:10 +00:00
|
|
|
if exists {
|
2019-01-21 20:11:40 +00:00
|
|
|
profileStore.Shutdown()
|
|
|
|
log.Errorf("profile for onion %v already exists", profile.Onion)
|
2018-09-21 18:53:10 +00:00
|
|
|
continue
|
|
|
|
}
|
2018-11-22 00:08:47 +00:00
|
|
|
|
2019-01-21 20:11:40 +00:00
|
|
|
peer := peer.FromProfile(profile)
|
|
|
|
peer.Init(app.acn, app.eventBus)
|
2018-11-22 00:08:47 +00:00
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
app.mutex.Lock()
|
2019-01-21 20:11:40 +00:00
|
|
|
app.peers[profile.Onion] = peer
|
|
|
|
app.storage[profile.Onion] = profileStore
|
2018-10-04 04:35:30 +00:00
|
|
|
if app.primaryonion == "" {
|
2019-01-21 20:11:40 +00:00
|
|
|
app.primaryonion = profile.Onion
|
2018-10-04 04:35:30 +00:00
|
|
|
}
|
2018-09-21 18:53:10 +00:00
|
|
|
app.mutex.Unlock()
|
|
|
|
}
|
|
|
|
return nil
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-22 00:08:47 +00:00
|
|
|
func (app *application) LaunchPeers() {
|
|
|
|
for _, p := range app.peers {
|
|
|
|
if !p.IsStarted() {
|
2018-11-26 22:06:26 +00:00
|
|
|
p.Listen()
|
2018-11-22 00:08:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
// ListPeers returns a map of onions to their profile's Name
|
|
|
|
func (app *application) ListPeers() map[string]string {
|
|
|
|
keys := map[string]string{}
|
|
|
|
for k, p := range app.peers {
|
|
|
|
keys[k] = p.GetProfile().Name
|
|
|
|
}
|
|
|
|
return keys
|
|
|
|
}
|
2018-07-10 20:42:47 +00:00
|
|
|
|
2018-10-06 03:50:55 +00:00
|
|
|
// PrimaryIdentity returns a cwtchPeer for a given onion address
|
2018-10-04 04:35:30 +00:00
|
|
|
func (app *application) PrimaryIdentity() peer.CwtchPeer {
|
|
|
|
return app.peers[app.primaryonion]
|
|
|
|
}
|
|
|
|
|
2018-10-06 03:50:55 +00:00
|
|
|
// GetPeer returns a cwtchPeer for a given onion address
|
2018-09-21 18:53:10 +00:00
|
|
|
func (app *application) GetPeer(onion string) peer.CwtchPeer {
|
|
|
|
if peer, ok := app.peers[onion]; ok {
|
|
|
|
return peer
|
|
|
|
}
|
2018-07-10 20:42:47 +00:00
|
|
|
return nil
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-10 22:14:12 +00:00
|
|
|
/*
|
2018-10-05 23:27:57 +00:00
|
|
|
// GetTorStatus returns tor control port bootstrap-phase status info in a map
|
|
|
|
func (app *application) GetTorStatus() (map[string]string, error) {
|
|
|
|
return app.torManager.GetStatus()
|
2018-11-10 22:14:12 +00:00
|
|
|
}*/
|
2018-10-05 23:27:57 +00:00
|
|
|
|
2019-01-19 23:16:38 +00:00
|
|
|
// Fetch the app's event manager
|
|
|
|
func (app *application) EventBus() *event.Manager {
|
|
|
|
return app.eventBus
|
|
|
|
}
|
|
|
|
|
2018-09-21 18:53:10 +00:00
|
|
|
// Shutdown shutsdown all peers of an app and then the tormanager
|
|
|
|
func (app *application) Shutdown() {
|
|
|
|
for _, peer := range app.peers {
|
|
|
|
peer.Shutdown()
|
|
|
|
}
|
2018-04-30 21:47:21 +00:00
|
|
|
}
|