Official cwtch.im peer and server implementations. https://cwtch.im
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

314 рядки
11KB

  1. package connections
  2. import (
  3. "cwtch.im/cwtch/event"
  4. "cwtch.im/cwtch/protocol"
  5. "cwtch.im/tapir"
  6. "cwtch.im/tapir/applications"
  7. "cwtch.im/tapir/networks/tor"
  8. "cwtch.im/tapir/primitives"
  9. "errors"
  10. "git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
  11. "git.openprivacy.ca/openprivacy/libricochet-go/log"
  12. "github.com/golang/protobuf/proto"
  13. "golang.org/x/crypto/ed25519"
  14. "sync"
  15. "time"
  16. )
  17. type engine struct {
  18. queue event.Queue
  19. connectionsManager *Manager
  20. // Engine Attributes
  21. identity primitives.Identity
  22. acn connectivity.ACN
  23. // Engine State
  24. started bool
  25. // Blocklist
  26. blocked sync.Map
  27. // Pointer to the Global Event Manager
  28. eventManager event.Manager
  29. // Nextgen Tapir Service
  30. service tapir.Service
  31. // Required for listen(), inaccessible from identity
  32. privateKey ed25519.PrivateKey
  33. shuttingDown bool
  34. }
  35. // Engine (ProtocolEngine) encapsulates the logic necessary to make and receive Cwtch connections.
  36. // Note: ProtocolEngine doesn't have access to any information necessary to encrypt or decrypt GroupMessages
  37. type Engine interface {
  38. ACN() connectivity.ACN
  39. EventManager() event.Manager
  40. Shutdown()
  41. }
  42. // NewProtocolEngine initializes a new engine that runs Cwtch using the given parameters
  43. func NewProtocolEngine(identity primitives.Identity, privateKey ed25519.PrivateKey, acn connectivity.ACN, eventManager event.Manager, blockedPeers []string) Engine {
  44. engine := new(engine)
  45. engine.identity = identity
  46. engine.privateKey = privateKey
  47. engine.queue = event.NewQueue()
  48. go engine.eventHandler()
  49. engine.acn = acn
  50. engine.connectionsManager = NewConnectionsManager(engine.acn)
  51. go engine.connectionsManager.AttemptReconnections()
  52. // Init the Server running the Simple App.
  53. engine.service = new(tor.BaseOnionService)
  54. engine.service.Init(acn, privateKey, &identity)
  55. engine.eventManager = eventManager
  56. engine.eventManager.Subscribe(event.ProtocolEngineStartListen, engine.queue)
  57. engine.eventManager.Subscribe(event.PeerRequest, engine.queue)
  58. engine.eventManager.Subscribe(event.InvitePeerToGroup, engine.queue)
  59. engine.eventManager.Subscribe(event.JoinServer, engine.queue)
  60. engine.eventManager.Subscribe(event.SendMessageToGroup, engine.queue)
  61. engine.eventManager.Subscribe(event.SendMessageToPeer, engine.queue)
  62. engine.eventManager.Subscribe(event.DeleteContact, engine.queue)
  63. engine.eventManager.Subscribe(event.DeleteGroup, engine.queue)
  64. engine.eventManager.Subscribe(event.BlockPeer, engine.queue)
  65. engine.eventManager.Subscribe(event.UnblockPeer, engine.queue)
  66. for _, peer := range blockedPeers {
  67. engine.blocked.Store(peer, true)
  68. }
  69. return engine
  70. }
  71. func (e *engine) ACN() connectivity.ACN {
  72. return e.acn
  73. }
  74. func (e *engine) EventManager() event.Manager {
  75. return e.eventManager
  76. }
  77. // eventHandler process events from other subsystems
  78. func (e *engine) eventHandler() {
  79. for {
  80. ev := e.queue.Next()
  81. switch ev.EventType {
  82. case event.StatusRequest:
  83. e.eventManager.Publish(event.Event{EventType: event.ProtocolEngineStatus, EventID: ev.EventID})
  84. case event.PeerRequest:
  85. go e.peerWithOnion(ev.Data[event.RemotePeer])
  86. case event.InvitePeerToGroup:
  87. e.sendMessageToPeer(ev.EventID, ev.Data[event.RemotePeer], event.ContextInvite, []byte(ev.Data[event.GroupInvite]))
  88. case event.JoinServer:
  89. e.joinServer(ev.Data[event.GroupServer])
  90. case event.DeleteContact:
  91. onion := ev.Data[event.RemotePeer]
  92. e.deleteConnection(onion)
  93. case event.DeleteGroup:
  94. // TODO: There isn't a way here to determine if other Groups are using a server connection...
  95. case event.SendMessageToGroup:
  96. e.sendMessageToGroup(ev.Data[event.GroupServer], []byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature]))
  97. case event.SendMessageToPeer:
  98. // TODO: remove this passthrough once the UI is integrated.
  99. context, ok := ev.Data[event.EventContext]
  100. if !ok {
  101. context = event.ContextRaw
  102. }
  103. err := e.sendMessageToPeer(ev.EventID, ev.Data[event.RemotePeer], context, []byte(ev.Data[event.Data]))
  104. if err != nil {
  105. 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"}))
  106. }
  107. case event.UnblockPeer:
  108. // We simply remove the peer from our blocklist
  109. // The UI has the responsibility to reinitiate contact with the peer.
  110. // (this should happen periodically in any case)
  111. e.blocked.Delete(ev.Data[event.RemotePeer])
  112. case event.BlockPeer:
  113. e.blocked.Store(ev.Data[event.RemotePeer], true)
  114. connection, err := e.service.GetConnection(ev.Data[event.RemotePeer])
  115. if connection != nil && err == nil {
  116. connection.Close()
  117. }
  118. // Explicitly send a disconnected event (if we don't do this here then the UI can wait for a while before
  119. // an ongoing Open() connection fails and so the user will see a blocked peer as still connecting (because
  120. // there isn't an active connection and we are stuck waiting for tor to time out)
  121. e.peerDisconnected(ev.Data[event.RemotePeer])
  122. case event.ProtocolEngineStartListen:
  123. go e.listenFn()
  124. default:
  125. return
  126. }
  127. }
  128. }
  129. func (e *engine) createPeerTemplate() *PeerApp {
  130. peerAppTemplate := new(PeerApp)
  131. peerAppTemplate.IsBlocked = func(onion string) bool {
  132. _, blocked := e.blocked.Load(onion)
  133. return blocked
  134. }
  135. peerAppTemplate.MessageHandler = e.handlePeerMessage
  136. peerAppTemplate.OnAcknowledgement = e.ignoreOnShutdown2(e.peerAck)
  137. peerAppTemplate.OnAuth = e.ignoreOnShutdown(e.peerAuthed)
  138. peerAppTemplate.OnConnecting = e.ignoreOnShutdown(e.peerConnecting)
  139. peerAppTemplate.OnClose = e.ignoreOnShutdown(e.peerDisconnected)
  140. return peerAppTemplate
  141. }
  142. // Listen sets up an onion listener to process incoming cwtch messages
  143. func (e *engine) listenFn() {
  144. err := e.service.Listen(e.createPeerTemplate())
  145. if !e.shuttingDown {
  146. e.eventManager.Publish(event.NewEvent(event.ProtocolEngineStopped, map[event.Field]string{event.Identity: e.identity.Hostname(), event.Error: err.Error()}))
  147. }
  148. return
  149. }
  150. // Shutdown tears down the eventHandler goroutine
  151. func (e *engine) Shutdown() {
  152. e.shuttingDown = true
  153. e.connectionsManager.Shutdown()
  154. e.service.Shutdown()
  155. e.queue.Shutdown()
  156. }
  157. // peerWithOnion is the entry point for cwtchPeer relationships
  158. // needs to be run in a goroutine as will block on Open.
  159. func (e *engine) peerWithOnion(onion string) {
  160. _, blocked := e.blocked.Load(onion)
  161. if !blocked {
  162. e.ignoreOnShutdown(e.peerConnecting)(onion)
  163. connected, err := e.service.Connect(onion, e.createPeerTemplate())
  164. // If we are already connected...check if we are authed and issue an auth event
  165. // (This allows the ui to be stateless)
  166. if connected && err != nil {
  167. conn, err := e.service.GetConnection(onion)
  168. if err == nil {
  169. if conn.HasCapability(applications.AuthCapability) {
  170. e.ignoreOnShutdown(e.peerAuthed)(onion)
  171. return
  172. }
  173. }
  174. }
  175. // Only issue a disconnected error if we are disconnected (Connect will fail if a connection already exists)
  176. if !connected && err != nil {
  177. e.ignoreOnShutdown(e.peerDisconnected)(onion)
  178. }
  179. }
  180. }
  181. func (e *engine) ignoreOnShutdown(f func(string)) func(string) {
  182. return func(x string) {
  183. if !e.shuttingDown {
  184. f(x)
  185. }
  186. }
  187. }
  188. func (e *engine) ignoreOnShutdown2(f func(string, string)) func(string, string) {
  189. return func(x, y string) {
  190. if !e.shuttingDown {
  191. f(x, y)
  192. }
  193. }
  194. }
  195. func (e *engine) peerAuthed(onion string) {
  196. e.eventManager.Publish(event.NewEvent(event.PeerStateChange, map[event.Field]string{
  197. event.RemotePeer: string(onion),
  198. event.ConnectionState: ConnectionStateName[AUTHENTICATED],
  199. }))
  200. }
  201. func (e *engine) peerConnecting(onion string) {
  202. e.eventManager.Publish(event.NewEvent(event.PeerStateChange, map[event.Field]string{
  203. event.RemotePeer: string(onion),
  204. event.ConnectionState: ConnectionStateName[CONNECTING],
  205. }))
  206. }
  207. func (e *engine) peerAck(onion string, eventID string) {
  208. e.eventManager.Publish(event.NewEvent(event.PeerAcknowledgement, map[event.Field]string{
  209. event.EventID: eventID,
  210. event.RemotePeer: onion,
  211. }))
  212. }
  213. func (e *engine) peerDisconnected(onion string) {
  214. e.eventManager.Publish(event.NewEvent(event.PeerStateChange, map[event.Field]string{
  215. event.RemotePeer: string(onion),
  216. event.ConnectionState: ConnectionStateName[DISCONNECTED],
  217. }))
  218. }
  219. // sendMessageToPeer sends a message to a peer under a given context
  220. func (e *engine) sendMessageToPeer(eventID string, onion string, context string, message []byte) error {
  221. conn, err := e.service.GetConnection(onion)
  222. if err == nil {
  223. peerApp, ok := (conn.App()).(*PeerApp)
  224. if ok {
  225. peerApp.SendMessage(PeerMessage{eventID, context, message})
  226. return nil
  227. }
  228. return errors.New("failed type assertion conn.App != PeerApp")
  229. }
  230. return err
  231. }
  232. func (e *engine) deleteConnection(id string) {
  233. conn, err := e.service.GetConnection(id)
  234. if err == nil {
  235. conn.Close()
  236. }
  237. }
  238. // receiveGroupMessage is a callback function that processes GroupMessages from a given server
  239. func (e *engine) receiveGroupMessage(server string, gm *protocol.GroupMessage) {
  240. // Publish Event so that a Profile Engine can deal with it.
  241. // Note: This technically means that *multiple* Profile Engines could listen to the same ProtocolEngine!
  242. e.eventManager.Publish(event.NewEvent(event.EncryptedGroupMessage, map[event.Field]string{event.Ciphertext: string(gm.GetCiphertext()), event.Signature: string(gm.GetSignature())}))
  243. }
  244. // joinServer manages a new server connection with the given onion address
  245. func (e *engine) joinServer(onion string) {
  246. e.connectionsManager.ManageServerConnection(onion, e, e.receiveGroupMessage)
  247. }
  248. // sendMessageToGroup attempts to sent the given message to the given group id.
  249. func (e *engine) sendMessageToGroup(server string, ct []byte, sig []byte) {
  250. psc := e.connectionsManager.GetPeerServerConnectionForOnion(server)
  251. if psc == nil {
  252. 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"}))
  253. }
  254. gm := &protocol.GroupMessage{
  255. Ciphertext: ct,
  256. Signature: sig,
  257. }
  258. err := psc.SendGroupMessage(gm)
  259. if err != nil {
  260. e.eventManager.Publish(event.NewEvent(event.SendMessageToGroupError, map[event.Field]string{event.GroupServer: server, event.Signature: string(sig), event.Error: err.Error()}))
  261. }
  262. }
  263. func (e *engine) handlePeerMessage(hostname string, context string, message []byte) {
  264. log.Debugf("New message from peer: %v %v", hostname, context)
  265. if context == event.ContextInvite {
  266. cpp := &protocol.CwtchPeerPacket{}
  267. err := proto.Unmarshal(message, cpp)
  268. if err == nil && cpp.GetGroupChatInvite() != nil {
  269. marshal, _ := proto.Marshal(cpp.GetGroupChatInvite())
  270. e.eventManager.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: hostname, event.GroupInvite: string(marshal)}))
  271. }
  272. } else {
  273. e.eventManager.Publish(event.NewEvent(event.NewMessageFromPeer, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: hostname, event.Data: string(message)}))
  274. }
  275. }