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.

engine.go 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. package connections
  2. import (
  3. "crypto/rsa"
  4. "cwtch.im/cwtch/event"
  5. "cwtch.im/cwtch/protocol"
  6. "cwtch.im/cwtch/protocol/connections/peer"
  7. "errors"
  8. "git.openprivacy.ca/openprivacy/libricochet-go/application"
  9. "git.openprivacy.ca/openprivacy/libricochet-go/channels"
  10. "git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
  11. "git.openprivacy.ca/openprivacy/libricochet-go/identity"
  12. "git.openprivacy.ca/openprivacy/libricochet-go/log"
  13. "github.com/golang/protobuf/proto"
  14. "golang.org/x/crypto/ed25519"
  15. "sync"
  16. "time"
  17. )
  18. type engine struct {
  19. queue *event.Queue
  20. connectionsManager *Manager
  21. // Engine Attributes
  22. identity identity.Identity
  23. acn connectivity.ACN
  24. app *application.RicochetApplication
  25. // Engine State
  26. started bool
  27. // Blocklist
  28. blocked sync.Map
  29. // Pointer to the Global Event Manager
  30. eventManager event.Manager
  31. // Required for listen(), inaccessible from identity
  32. privateKey ed25519.PrivateKey
  33. }
  34. // Engine (ProtocolEngine) encapsulates the logic necessary to make and receive Cwtch connections.
  35. // Note: ProtocolEngine doesn't have access to any information necessary to encrypt or decrypt GroupMessages
  36. type Engine interface {
  37. Identity() identity.Identity
  38. ACN() connectivity.ACN
  39. EventManager() event.Manager
  40. GetPeerHandler(string) *CwtchPeerHandler
  41. ContactRequest(string, string) string
  42. LookupContact(string, rsa.PublicKey) (bool, bool)
  43. LookupContactV3(string, ed25519.PublicKey) (bool, bool)
  44. Shutdown()
  45. }
  46. // NewProtocolEngine initializes a new engine that runs Cwtch using the given parameters
  47. func NewProtocolEngine(identity identity.Identity, privateKey ed25519.PrivateKey, acn connectivity.ACN, eventManager event.Manager, blockedPeers []string) Engine {
  48. engine := new(engine)
  49. engine.identity = identity
  50. engine.privateKey = privateKey
  51. engine.queue = event.NewEventQueue(100)
  52. go engine.eventHandler()
  53. engine.acn = acn
  54. engine.connectionsManager = NewConnectionsManager(engine.acn)
  55. go engine.connectionsManager.AttemptReconnections()
  56. engine.eventManager = eventManager
  57. engine.eventManager.Subscribe(event.ProtocolEngineStartListen, engine.queue.EventChannel)
  58. engine.eventManager.Subscribe(event.PeerRequest, engine.queue.EventChannel)
  59. engine.eventManager.Subscribe(event.InvitePeerToGroup, engine.queue.EventChannel)
  60. engine.eventManager.Subscribe(event.JoinServer, engine.queue.EventChannel)
  61. engine.eventManager.Subscribe(event.SendMessageToGroup, engine.queue.EventChannel)
  62. engine.eventManager.Subscribe(event.SendMessageToPeer, engine.queue.EventChannel)
  63. engine.eventManager.Subscribe(event.BlockPeer, engine.queue.EventChannel)
  64. for _, peer := range blockedPeers {
  65. engine.blocked.Store(peer, true)
  66. }
  67. return engine
  68. }
  69. func (e *engine) ACN() connectivity.ACN {
  70. return e.acn
  71. }
  72. func (e *engine) Identity() identity.Identity {
  73. return e.identity
  74. }
  75. func (e *engine) EventManager() event.Manager {
  76. return e.eventManager
  77. }
  78. // eventHandler process events from other subsystems
  79. func (e *engine) eventHandler() {
  80. for {
  81. ev := e.queue.Next()
  82. switch ev.EventType {
  83. case event.StatusRequest:
  84. e.eventManager.Publish(event.Event{EventType: event.ProtocolEngineStatus, EventID: ev.EventID})
  85. case event.PeerRequest:
  86. e.peerWithOnion(ev.Data[event.RemotePeer])
  87. case event.InvitePeerToGroup:
  88. e.inviteOnionToGroup(ev.Data[event.RemotePeer], []byte(ev.Data[event.GroupInvite]))
  89. case event.JoinServer:
  90. e.joinServer(ev.Data[event.GroupServer])
  91. case event.SendMessageToGroup:
  92. e.sendMessageToGroup(ev.Data[event.GroupServer], []byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature]))
  93. case event.SendMessageToPeer:
  94. log.Debugf("Sending Message to Peer.....")
  95. ppc := e.connectionsManager.GetPeerPeerConnectionForOnion(ev.Data[event.RemotePeer])
  96. if ppc != nil && ppc.GetState() == AUTHENTICATED {
  97. err := ppc.SendPacket([]byte(ev.Data[event.Data]))
  98. if err != nil {
  99. e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: ev.Data[event.RemotePeer], event.Signature: ev.EventID, event.Error: err.Error()}))
  100. }
  101. } else {
  102. e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.RemotePeer: ev.Data[event.RemotePeer], event.Signature: ev.EventID, event.Error: "peer is offline or the connection has yet to finalize"}))
  103. }
  104. case event.BlockPeer:
  105. e.blocked.Store(ev.Data[event.RemotePeer], true)
  106. ppc := e.connectionsManager.GetPeerPeerConnectionForOnion(ev.Data[event.RemotePeer])
  107. if ppc != nil {
  108. ppc.Close()
  109. }
  110. e.app.Close(ev.Data[event.RemotePeer])
  111. case event.ProtocolEngineStartListen:
  112. go e.listenFn()
  113. default:
  114. return
  115. }
  116. }
  117. }
  118. // GetPeerHandler is an external interface function that allows callers access to a CwtchPeerHandler
  119. // TODO: There is likely a slightly better way to encapsulate this behavior
  120. func (e *engine) GetPeerHandler(remotePeerHostname string) *CwtchPeerHandler {
  121. return &CwtchPeerHandler{Onion: remotePeerHostname, EventBus: e.eventManager}
  122. }
  123. // Listen sets up an onion listener to process incoming cwtch messages
  124. func (e *engine) listenFn() {
  125. ra := new(application.RicochetApplication)
  126. onionService, err := e.acn.Listen(e.privateKey, application.RicochetPort)
  127. if err != nil /*&& fmt.Sprintf("%v", err) != "550 Unspecified Tor error: Onion address collision"*/ {
  128. e.eventManager.Publish(event.NewEvent(event.ProtocolEngineStopped, map[event.Field]string{event.Identity: e.identity.Hostname(), event.Error: err.Error()}))
  129. return
  130. }
  131. af := application.InstanceFactory{}
  132. af.Init()
  133. af.AddHandler("im.cwtch.peer", func(rai *application.Instance) func() channels.Handler {
  134. cpi := new(CwtchPeerInstance)
  135. cpi.Init(rai, ra)
  136. return func() channels.Handler {
  137. cpc := new(peer.CwtchPeerChannel)
  138. cpc.Handler = e.GetPeerHandler(rai.RemoteHostname)
  139. return cpc
  140. }
  141. })
  142. af.AddHandler("im.cwtch.peer.data", func(rai *application.Instance) func() channels.Handler {
  143. cpi := new(CwtchPeerInstance)
  144. cpi.Init(rai, ra)
  145. return func() channels.Handler {
  146. cpc := new(peer.CwtchPeerDataChannel)
  147. cpc.Handler = e.GetPeerHandler(rai.RemoteHostname)
  148. return cpc
  149. }
  150. })
  151. ra.Init(e.ACN(), e.identity.Name, e.identity, af, e)
  152. log.Infof("Running cwtch peer on %v", onionService.AddressFull())
  153. e.started = true
  154. e.app = ra
  155. ra.Run(onionService)
  156. e.eventManager.Publish(event.NewEvent(event.ProtocolEngineStopped, map[event.Field]string{event.Identity: e.identity.Hostname()}))
  157. return
  158. }
  159. // LookupContact is a V2 API Call, we want to reject all V2 Peers
  160. // TODO Deprecate
  161. func (e *engine) LookupContact(hostname string, publicKey rsa.PublicKey) (allowed, known bool) {
  162. return false, false
  163. }
  164. // ContactRequest is a V2 API Call needed to implement ContactRequestHandler Interface
  165. // TODO Deprecate
  166. func (e *engine) ContactRequest(name string, message string) string {
  167. return "Rejected"
  168. }
  169. // LookupContactV3 returns that a contact is known and allowed to communicate for all cases.
  170. func (e *engine) LookupContactV3(hostname string, publicKey ed25519.PublicKey) (allowed, known bool) {
  171. // TODO: We want to autoblock those that are blocked, The known parameter has no use anymore and should be
  172. // disregarded by peers, so we set it to false.
  173. if _, blocked := e.blocked.Load(hostname); blocked {
  174. return false, false
  175. }
  176. return true, false
  177. }
  178. // Shutdown tears down the eventHandler goroutine
  179. func (e *engine) Shutdown() {
  180. e.connectionsManager.Shutdown()
  181. e.app.Shutdown()
  182. e.queue.Shutdown()
  183. }
  184. // peerWithOnion is the entry point for cwtchPeer relationships
  185. func (e *engine) peerWithOnion(onion string) *PeerPeerConnection {
  186. return e.connectionsManager.ManagePeerConnection(onion, e)
  187. }
  188. // inviteOnionToGroup kicks off the invite process
  189. func (e *engine) inviteOnionToGroup(onion string, invite []byte) error {
  190. ppc := e.connectionsManager.GetPeerPeerConnectionForOnion(onion)
  191. if ppc == nil {
  192. return errors.New("peer connection not setup for onion. peers must be trusted before sending")
  193. }
  194. if ppc.GetState() == AUTHENTICATED {
  195. log.Infof("Got connection for group: %v - Sending Invite\n", ppc)
  196. ppc.SendGroupInvite(invite)
  197. } else {
  198. return errors.New("cannot send invite to onion: peer connection is not ready")
  199. }
  200. return nil
  201. }
  202. // receiveGroupMessage is a callback function that processes GroupMessages from a given server
  203. func (e *engine) receiveGroupMessage(server string, gm *protocol.GroupMessage) {
  204. // Publish Event so that a Profile Engine can deal with it.
  205. // Note: This technically means that *multiple* Profile Engines could listen to the same ProtocolEngine!
  206. e.eventManager.Publish(event.NewEvent(event.EncryptedGroupMessage, map[event.Field]string{event.Ciphertext: string(gm.GetCiphertext()), event.Signature: string(gm.GetSignature())}))
  207. }
  208. // finishedFetch is a callback function the processes the termination of a fetch channel from a given server
  209. func (e *engine) finishedFetch(server string) {
  210. e.eventManager.Publish(event.NewEvent(event.FinishedFetch, map[event.Field]string{event.GroupServer: server}))
  211. }
  212. // joinServer manages a new server connection with the given onion address
  213. func (e *engine) joinServer(onion string) {
  214. e.connectionsManager.ManageServerConnection(onion, e, e.receiveGroupMessage, e.finishedFetch)
  215. }
  216. // sendMessageToGroup attempts to sent the given message to the given group id.
  217. func (e *engine) sendMessageToGroup(server string, ct []byte, sig []byte) {
  218. psc := e.connectionsManager.GetPeerServerConnectionForOnion(server)
  219. if psc == nil {
  220. e.eventManager.Publish(event.NewEvent(event.SendMessageToGroupError, map[event.Field]string{event.GroupServer: server, event.Signature: string(sig), event.Error: "server is offline or the connection has yet to finalize"}))
  221. }
  222. gm := &protocol.GroupMessage{
  223. Ciphertext: ct,
  224. Signature: sig,
  225. }
  226. err := psc.SendGroupMessage(gm)
  227. if err != nil {
  228. e.eventManager.Publish(event.NewEvent(event.SendMessageToGroupError, map[event.Field]string{event.GroupServer: server, event.Signature: string(sig), event.Error: err.Error()}))
  229. }
  230. }
  231. // CwtchPeerInstance encapsulates incoming peer connections
  232. type CwtchPeerInstance struct {
  233. rai *application.Instance
  234. ra *application.RicochetApplication
  235. }
  236. // Init sets up a CwtchPeerInstance
  237. func (cpi *CwtchPeerInstance) Init(rai *application.Instance, ra *application.RicochetApplication) {
  238. cpi.rai = rai
  239. cpi.ra = ra
  240. }
  241. // CwtchPeerHandler encapsulates handling of incoming CwtchPackets
  242. type CwtchPeerHandler struct {
  243. Onion string
  244. EventBus event.Manager
  245. DataHandler func(string, []byte) []byte
  246. }
  247. // HandleGroupInvite handles incoming GroupInvites
  248. func (cph *CwtchPeerHandler) HandleGroupInvite(gci *protocol.GroupChatInvite) {
  249. log.Debugf("Received GroupID from %v %v\n", cph.Onion, gci.String())
  250. marshal, err := proto.Marshal(gci)
  251. if err == nil {
  252. cph.EventBus.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: cph.Onion, event.GroupInvite: string(marshal)}))
  253. }
  254. }
  255. // HandlePacket handles the Cwtch cwtchPeer Data Channel
  256. func (cph *CwtchPeerHandler) HandlePacket(data []byte) []byte {
  257. cph.EventBus.Publish(event.NewEvent(event.NewMessageFromPeer, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: cph.Onion, event.Data: string(data)}))
  258. return []byte{} // TODO remove this
  259. }