cwtch/app/app.go

167 lines
4.2 KiB
Go

package app
import (
"crypto/rand"
"cwtch.im/cwtch/peer"
"cwtch.im/cwtch/storage"
"encoding/hex"
"fmt"
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"io/ioutil"
"os"
"path"
"path/filepath"
"sync"
)
type application struct {
peers map[string]peer.CwtchPeer
acn connectivity.ACN
directory string
mutex sync.Mutex
primaryonion string
storage map[string]storage.ProfileStore
}
// Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
type Application interface {
SaveProfile(cwtchPeer peer.CwtchPeer)
LoadProfiles(password string) error
CreatePeer(name string, password string) (peer.CwtchPeer, error)
PrimaryIdentity() peer.CwtchPeer
GetPeer(onion string) peer.CwtchPeer
ListPeers() map[string]string
LaunchPeers()
//GetTorStatus() (map[string]string, error)
Shutdown()
}
// NewApp creates a new app with some environment awareness and initializes a Tor Manager
func NewApp(acn connectivity.ACN, appDirectory string) Application {
log.Debugf("NewApp(%v)\n", appDirectory)
app := &application{peers: make(map[string]peer.CwtchPeer), storage: make(map[string]storage.ProfileStore), directory: appDirectory, acn: acn}
os.Mkdir(path.Join(app.directory, "profiles"), 0700)
return app
}
func generateRandomFilename() string {
randBytes := make([]byte, 16)
rand.Read(randBytes)
return filepath.Join(hex.EncodeToString(randBytes))
}
func (app *application) SaveProfile(p peer.CwtchPeer) {
app.mutex.Lock()
defer app.mutex.Unlock()
app.peers[p.GetProfile().Onion] = p
app.storage[p.GetProfile().Onion].Save(p)
}
// NewProfile creates a new cwtchPeer with a given name.
func (app *application) CreatePeer(name string, password string) (peer.CwtchPeer, error) {
log.Debugf("CreatePeer(%v)\n", name)
randomFileName := generateRandomFilename()
fileStore := storage.CreateFileProfileStore(path.Join(app.directory, "profiles", randomFileName), password)
p := peer.NewCwtchPeer(name)
err := fileStore.Save(p)
if err != nil {
return nil, err
}
p.Init(app.acn)
_, exists := app.peers[p.GetProfile().Onion]
if exists {
p.Shutdown()
return nil, fmt.Errorf("Error: profile for onion %v already exists", p.GetProfile().Onion)
}
app.mutex.Lock()
app.peers[p.GetProfile().Onion] = p
app.storage[p.GetProfile().Onion] = fileStore
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 {
fileStore := storage.CreateFileProfileStore(path.Join(app.directory, "profiles", file.Name()), password)
p, err := fileStore.Load()
if err != nil {
continue
}
_, exists := app.peers[p.GetProfile().Onion]
if exists {
p.Shutdown()
log.Errorf("profile for onion %v already exists", p.GetProfile().Onion)
continue
}
p.Init(app.acn)
app.mutex.Lock()
app.peers[p.GetProfile().Onion] = p
app.storage[p.GetProfile().Onion] = fileStore
if app.primaryonion == "" {
app.primaryonion = p.GetProfile().Onion
}
app.mutex.Unlock()
}
return nil
}
func (app *application) LaunchPeers() {
for _, p := range app.peers {
if !p.IsStarted() {
p.Listen()
}
}
}
// 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
}
// PrimaryIdentity returns a cwtchPeer for a given onion address
func (app *application) PrimaryIdentity() peer.CwtchPeer {
return app.peers[app.primaryonion]
}
// GetPeer returns a cwtchPeer for a given onion address
func (app *application) GetPeer(onion string) peer.CwtchPeer {
if peer, ok := app.peers[onion]; ok {
return peer
}
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()
}
}