Official cwtch.im peer and server implementations. https://cwtch.im
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

app.go 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package app
  2. import (
  3. "cwtch.im/cwtch/event"
  4. "cwtch.im/cwtch/model"
  5. "cwtch.im/cwtch/peer"
  6. "cwtch.im/cwtch/protocol/connections"
  7. "cwtch.im/cwtch/storage"
  8. "fmt"
  9. "git.openprivacy.ca/openprivacy/libricochet-go/identity"
  10. "git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
  11. "git.openprivacy.ca/openprivacy/libricochet-go/log"
  12. "io/ioutil"
  13. "os"
  14. "path"
  15. "sync"
  16. )
  17. type applicationCore struct {
  18. eventBuses map[string]event.Manager
  19. acn connectivity.ACN
  20. directory string
  21. mutex sync.Mutex
  22. }
  23. type applicationPeers struct {
  24. peers map[string]peer.CwtchPeer
  25. }
  26. type application struct {
  27. applicationCore
  28. applicationPeers
  29. storage map[string]storage.ProfileStore
  30. engines map[string]connections.Engine
  31. appBus event.Manager
  32. }
  33. // Application is a full cwtch peer application. It allows management, usage and storage of multiple peers
  34. type Application interface {
  35. LoadProfiles(password string)
  36. CreatePeer(name string, password string)
  37. LaunchPeers()
  38. GetPrimaryBus() event.Manager
  39. GetEventBus(onion string) event.Manager
  40. ShutdownPeer(string)
  41. Shutdown()
  42. GetPeer(onion string) peer.CwtchPeer
  43. ListPeers() map[string]string
  44. }
  45. // LoadProfileFn is the function signature for a function in an app that loads a profile
  46. type LoadProfileFn func(profile *model.Profile, store storage.ProfileStore)
  47. func newAppCore(acn connectivity.ACN, appDirectory string) *applicationCore {
  48. appCore := &applicationCore{eventBuses: make(map[string]event.Manager), directory: appDirectory, acn: acn}
  49. os.MkdirAll(path.Join(appCore.directory, "profiles"), 0700)
  50. return appCore
  51. }
  52. // NewApp creates a new app with some environment awareness and initializes a Tor Manager
  53. func NewApp(acn connectivity.ACN, appDirectory string) Application {
  54. log.Debugf("NewApp(%v)\n", appDirectory)
  55. app := &application{storage: make(map[string]storage.ProfileStore), applicationPeers: applicationPeers{peers: make(map[string]peer.CwtchPeer)}, engines: make(map[string]connections.Engine), applicationCore: *newAppCore(acn, appDirectory), appBus: event.NewEventManager()}
  56. return app
  57. }
  58. // CreatePeer creates a new Peer with a given name and core required accessories (eventbus)
  59. func (ac *applicationCore) CreatePeer(name string, password string) (*model.Profile, error) {
  60. log.Debugf("CreatePeer(%v)\n", name)
  61. profile := storage.NewProfile(name)
  62. ac.mutex.Lock()
  63. defer ac.mutex.Unlock()
  64. _, exists := ac.eventBuses[profile.Onion]
  65. if exists {
  66. return nil, fmt.Errorf("Error: profile for onion %v already exists", profile.Onion)
  67. }
  68. eventBus := event.NewEventManager()
  69. ac.eventBuses[profile.Onion] = eventBus
  70. return profile, nil
  71. }
  72. // CreatePeer creates a new Peer with the given name and required accessories (eventbus, storage, protocol engine)
  73. func (app *application) CreatePeer(name string, password string) {
  74. profile, err := app.applicationCore.CreatePeer(name, password)
  75. if err != nil {
  76. app.appBus.Publish(event.NewEventList(event.PeerError, event.Error, err.Error()))
  77. return
  78. }
  79. profileStore := storage.NewProfileWriterStore(app.eventBuses[profile.Onion], path.Join(app.directory, "profiles", profile.LocalID), password, profile)
  80. app.storage[profile.Onion] = profileStore
  81. pc := app.storage[profile.Onion].GetProfileCopy()
  82. peer := peer.FromProfile(pc)
  83. peer.Init(app.acn, app.eventBuses[profile.Onion])
  84. blockedPeers := profile.BlockedPeers()
  85. // TODO: Would be nice if ProtocolEngine did not need to explicitly be given the Private Key.
  86. identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey)
  87. engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, app.acn, app.eventBuses[profile.Onion], blockedPeers)
  88. app.peers[profile.Onion] = peer
  89. app.engines[profile.Onion] = engine
  90. app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.Onion}))
  91. }
  92. // LoadProfiles takes a password and attempts to load any profiles it can from storage with it and create Peers for them
  93. func (ac *applicationCore) LoadProfiles(password string, loadProfileFn LoadProfileFn) error {
  94. files, err := ioutil.ReadDir(path.Join(ac.directory, "profiles"))
  95. if err != nil {
  96. return fmt.Errorf("Error: cannot read profiles directory: %v", err)
  97. }
  98. for _, file := range files {
  99. eventBus := event.NewEventManager()
  100. profileStore := storage.NewProfileWriterStore(eventBus, path.Join(ac.directory, "profiles", file.Name()), password, nil)
  101. err = profileStore.Load()
  102. if err != nil {
  103. continue
  104. }
  105. profile := profileStore.GetProfileCopy()
  106. _, exists := ac.eventBuses[profile.Onion]
  107. if exists {
  108. profileStore.Shutdown()
  109. eventBus.Shutdown()
  110. log.Errorf("profile for onion %v already exists", profile.Onion)
  111. continue
  112. }
  113. ac.mutex.Lock()
  114. ac.eventBuses[profile.Onion] = eventBus
  115. ac.mutex.Unlock()
  116. loadProfileFn(profile, profileStore)
  117. }
  118. return nil
  119. }
  120. // LoadProfiles takes a password and attempts to load any profiles it can from storage with it and create Peers for them
  121. func (app *application) LoadProfiles(password string) {
  122. app.applicationCore.LoadProfiles(password, func(profile *model.Profile, profileStore storage.ProfileStore) {
  123. peer := peer.FromProfile(profile)
  124. peer.Init(app.acn, app.eventBuses[profile.Onion])
  125. blockedPeers := profile.BlockedPeers()
  126. identity := identity.InitializeV3(profile.Name, &profile.Ed25519PrivateKey, &profile.Ed25519PublicKey)
  127. engine := connections.NewProtocolEngine(identity, profile.Ed25519PrivateKey, app.acn, app.eventBuses[profile.Onion], blockedPeers)
  128. app.mutex.Lock()
  129. app.peers[profile.Onion] = peer
  130. app.storage[profile.Onion] = profileStore
  131. app.engines[profile.Onion] = engine
  132. app.mutex.Unlock()
  133. app.appBus.Publish(event.NewEvent(event.NewPeer, map[event.Field]string{event.Identity: profile.Onion}))
  134. })
  135. }
  136. // GetPrimaryBus returns the bus the Application uses for events that aren't peer specific
  137. func (app *application) GetPrimaryBus() event.Manager {
  138. return app.appBus
  139. }
  140. // LaunchPeers starts each peer Listening and connecting to peers and groups
  141. func (appPeers *applicationPeers) LaunchPeers() {
  142. for _, p := range appPeers.peers {
  143. if !p.IsStarted() {
  144. p.Listen()
  145. p.StartPeersConnections()
  146. p.StartGroupConnections()
  147. }
  148. }
  149. }
  150. // ListPeers returns a map of onions to their profile's Name
  151. func (appPeers *applicationPeers) ListPeers() map[string]string {
  152. keys := map[string]string{}
  153. for k, p := range appPeers.peers {
  154. keys[k] = p.GetProfile().Name
  155. }
  156. return keys
  157. }
  158. // GetPeer returns a cwtchPeer for a given onion address
  159. func (appPeers *applicationPeers) GetPeer(onion string) peer.CwtchPeer {
  160. if peer, ok := appPeers.peers[onion]; ok {
  161. return peer
  162. }
  163. return nil
  164. }
  165. // GetEventBus returns a cwtchPeer's event bus
  166. func (ac *applicationCore) GetEventBus(onion string) event.Manager {
  167. if manager, ok := ac.eventBuses[onion]; ok {
  168. return manager
  169. }
  170. return nil
  171. }
  172. // ShutdownPeer shuts down a peer and removes it from the app's management
  173. func (app *application) ShutdownPeer(onion string) {
  174. app.mutex.Lock()
  175. defer app.mutex.Unlock()
  176. app.eventBuses[onion].Shutdown()
  177. delete(app.eventBuses, onion)
  178. app.peers[onion].Shutdown()
  179. delete(app.peers, onion)
  180. app.engines[onion].Shutdown()
  181. delete(app.engines, onion)
  182. app.storage[onion].Shutdown()
  183. delete(app.storage, onion)
  184. }
  185. // Shutdown shutsdown all peers of an app and then the tormanager
  186. func (app *application) Shutdown() {
  187. for id, peer := range app.peers {
  188. peer.Shutdown()
  189. app.engines[id].Shutdown()
  190. app.storage[id].Shutdown()
  191. app.eventBuses[id].Shutdown()
  192. }
  193. app.appBus.Shutdown()
  194. }