Official cwtch.im peer and server implementations. https://cwtch.im
No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

271 líneas
8.7KB

  1. package storage
  2. import (
  3. "cwtch.im/cwtch/event"
  4. "cwtch.im/cwtch/model"
  5. "cwtch.im/cwtch/protocol"
  6. "encoding/json"
  7. "git.openprivacy.ca/openprivacy/libricochet-go/log"
  8. "github.com/golang/protobuf/proto"
  9. "os"
  10. "time"
  11. )
  12. const profileFilename = "profile"
  13. type profileStore struct {
  14. fs FileStore
  15. streamStores map[string]StreamStore
  16. directory string
  17. password string
  18. profile *model.Profile
  19. eventManager event.Manager
  20. queue event.Queue
  21. writer bool
  22. }
  23. // ProfileStore is an interface to managing the storage of Cwtch Profiles
  24. type ProfileStore interface {
  25. Load() error
  26. Shutdown()
  27. GetProfileCopy(timeline bool) *model.Profile
  28. GetNewPeerMessage() *event.Event
  29. GetStatusMessages() []*event.Event
  30. }
  31. // NewProfileWriterStore returns a profile store backed by a filestore listening for events and saving them
  32. // directory should be $appDir/profiles/$rand
  33. func NewProfileWriterStore(eventManager event.Manager, directory, password string, profile *model.Profile) ProfileStore {
  34. os.Mkdir(directory, 0700)
  35. ps := &profileStore{fs: NewFileStore(directory, profileFilename, password), password: password, directory: directory, profile: profile, eventManager: eventManager, streamStores: map[string]StreamStore{}, writer: true}
  36. //ps.queue = event.NewQueue(100)
  37. ps.queue = event.NewQueue()
  38. if profile != nil {
  39. ps.save()
  40. }
  41. go ps.eventHandler()
  42. ps.eventManager.Subscribe(event.BlockPeer, ps.queue)
  43. ps.eventManager.Subscribe(event.UnblockPeer, ps.queue)
  44. ps.eventManager.Subscribe(event.PeerCreated, ps.queue)
  45. ps.eventManager.Subscribe(event.GroupCreated, ps.queue)
  46. ps.eventManager.Subscribe(event.SetProfileName, ps.queue)
  47. ps.eventManager.Subscribe(event.SetAttribute, ps.queue)
  48. ps.eventManager.Subscribe(event.SetPeerAttribute, ps.queue)
  49. ps.eventManager.Subscribe(event.SetGroupAttribute, ps.queue)
  50. ps.eventManager.Subscribe(event.AcceptGroupInvite, ps.queue)
  51. ps.eventManager.Subscribe(event.NewGroupInvite, ps.queue)
  52. ps.eventManager.Subscribe(event.NewMessageFromGroup, ps.queue)
  53. ps.eventManager.Subscribe(event.PeerStateChange, ps.queue)
  54. ps.eventManager.Subscribe(event.ServerStateChange, ps.queue)
  55. ps.eventManager.Subscribe(event.DeleteContact, ps.queue)
  56. ps.eventManager.Subscribe(event.DeleteGroup, ps.queue)
  57. return ps
  58. }
  59. // ReadProfile reads a profile from storqage and returns the profile
  60. // directory should be $appDir/profiles/$rand
  61. func ReadProfile(directory, password string) (*model.Profile, error) {
  62. os.Mkdir(directory, 0700)
  63. ps := &profileStore{fs: NewFileStore(directory, profileFilename, password), password: password, directory: directory, profile: nil, eventManager: nil, streamStores: map[string]StreamStore{}, writer: true}
  64. err := ps.Load()
  65. if err != nil {
  66. return nil, err
  67. }
  68. profile := ps.GetProfileCopy(true)
  69. return profile, nil
  70. }
  71. // NewProfile creates a new profile for use in the profile store.
  72. func NewProfile(name string) *model.Profile {
  73. profile := model.GenerateNewProfile(name)
  74. return profile
  75. }
  76. // GetNewPeerMessage is for AppService to call on Reload events, to reseed the AppClient with the loaded peers
  77. func (ps *profileStore) GetNewPeerMessage() *event.Event {
  78. message := event.NewEventList(event.NewPeer, event.Identity, ps.profile.LocalID, event.Password, ps.password, event.Status, "running")
  79. return &message
  80. }
  81. func (ps *profileStore) GetStatusMessages() []*event.Event {
  82. messages := []*event.Event{}
  83. for _, contact := range ps.profile.Contacts {
  84. message := event.NewEvent(event.PeerStateChange, map[event.Field]string{
  85. event.RemotePeer: string(contact.Onion),
  86. event.ConnectionState: contact.State,
  87. })
  88. messages = append(messages, &message)
  89. }
  90. doneServers := make(map[string]bool)
  91. for _, group := range ps.profile.Groups {
  92. if _, exists := doneServers[group.GroupServer]; !exists {
  93. message := event.NewEvent(event.ServerStateChange, map[event.Field]string{
  94. event.GroupServer: string(group.GroupServer),
  95. event.ConnectionState: group.State,
  96. })
  97. messages = append(messages, &message)
  98. doneServers[group.GroupServer] = true
  99. }
  100. }
  101. return messages
  102. }
  103. func (ps *profileStore) save() error {
  104. if ps.writer {
  105. bytes, _ := json.Marshal(ps.profile)
  106. return ps.fs.Save(bytes)
  107. }
  108. return nil
  109. }
  110. // Load instantiates a cwtchPeer from the file store
  111. func (ps *profileStore) Load() error {
  112. decrypted, err := ps.fs.Load()
  113. if err != nil {
  114. return err
  115. }
  116. cp := new(model.Profile)
  117. err = json.Unmarshal(decrypted, &cp)
  118. if err == nil {
  119. ps.profile = cp
  120. for gid, group := range cp.Groups {
  121. ss := NewStreamStore(ps.directory, group.LocalID, ps.password)
  122. cp.Groups[gid].Timeline.SetMessages(ss.Read())
  123. ps.streamStores[group.GroupID] = ss
  124. }
  125. }
  126. return err
  127. }
  128. func (ps *profileStore) GetProfileCopy(timeline bool) *model.Profile {
  129. return ps.profile.GetCopy(timeline)
  130. }
  131. func (ps *profileStore) eventHandler() {
  132. for {
  133. ev := ps.queue.Next()
  134. switch ev.EventType {
  135. case event.BlockPeer:
  136. contact, exists := ps.profile.GetContact(ev.Data[event.RemotePeer])
  137. if exists {
  138. contact.Blocked = true
  139. ps.save()
  140. }
  141. case event.UnblockPeer:
  142. contact, exists := ps.profile.GetContact(ev.Data[event.RemotePeer])
  143. if exists {
  144. contact.Blocked = false
  145. ps.save()
  146. }
  147. case event.PeerCreated:
  148. var pp *model.PublicProfile
  149. json.Unmarshal([]byte(ev.Data[event.Data]), &pp)
  150. ps.profile.AddContact(ev.Data[event.RemotePeer], pp)
  151. // TODO: configure - allow peers to be configured to turn on limited storage
  152. /*ss := NewStreamStore(ps.directory, pp.LocalID, ps.password)
  153. pp.Timeline.SetMessages(ss.Read())
  154. ps.streamStores[pp.Onion] = ss
  155. ps.save()*/
  156. case event.GroupCreated:
  157. var group *model.Group
  158. json.Unmarshal([]byte(ev.Data[event.Data]), &group)
  159. ps.profile.AddGroup(group)
  160. ps.streamStores[group.GroupID] = NewStreamStore(ps.directory, group.LocalID, ps.password)
  161. ps.save()
  162. case event.SetProfileName:
  163. ps.profile.Name = ev.Data[event.ProfileName]
  164. ps.profile.SetAttribute("name", ev.Data[event.ProfileName])
  165. ps.save()
  166. case event.SetAttribute:
  167. ps.profile.SetAttribute(ev.Data[event.Key], ev.Data[event.Data])
  168. ps.save()
  169. case event.SetPeerAttribute:
  170. contact, exists := ps.profile.GetContact(ev.Data[event.RemotePeer])
  171. if exists {
  172. contact.SetAttribute(ev.Data[event.Key], ev.Data[event.Data])
  173. ps.save()
  174. } else {
  175. log.Errorf("error setting attribute on peer %v peer does not exist", ev)
  176. }
  177. case event.SetGroupAttribute:
  178. group := ps.profile.GetGroupByGroupID(ev.Data[event.GroupID])
  179. if group != nil {
  180. group.SetAttribute(ev.Data[event.Key], ev.Data[event.Data])
  181. ps.save()
  182. } else {
  183. log.Errorf("error setting attribute on group %v group does not exist", ev)
  184. }
  185. case event.AcceptGroupInvite:
  186. err := ps.profile.AcceptInvite(ev.Data[event.GroupID])
  187. if err == nil {
  188. ps.save()
  189. } else {
  190. log.Errorf("error accepting group invite")
  191. }
  192. case event.NewGroupInvite:
  193. var gci protocol.GroupChatInvite
  194. err := proto.Unmarshal([]byte(ev.Data[event.GroupInvite]), &gci)
  195. if err == nil {
  196. ps.profile.ProcessInvite(&gci, ev.Data[event.RemotePeer])
  197. ps.save()
  198. group := ps.profile.Groups[gci.GetGroupName()]
  199. ps.streamStores[group.GroupID] = NewStreamStore(ps.directory, group.LocalID, ps.password)
  200. } else {
  201. log.Errorf("error storing new group invite: %v %v", ev, err)
  202. }
  203. case event.NewMessageFromGroup:
  204. groupid := ev.Data[event.GroupID]
  205. received, _ := time.Parse(time.RFC3339Nano, ev.Data[event.TimestampReceived])
  206. sent, _ := time.Parse(time.RFC3339Nano, ev.Data[event.TimestampSent])
  207. message := model.Message{Received: received, Timestamp: sent, Message: ev.Data[event.Data], PeerID: ev.Data[event.RemotePeer], Signature: []byte(ev.Data[event.Signature]), PreviousMessageSig: []byte(ev.Data[event.PreviousSignature])}
  208. ss, exists := ps.streamStores[groupid]
  209. if exists {
  210. ss.Write(message)
  211. } else {
  212. log.Errorf("error storing new group message: %v stream store does not exist", ev)
  213. }
  214. case event.PeerStateChange:
  215. if _, exists := ps.profile.Contacts[ev.Data[event.RemotePeer]]; exists {
  216. ps.profile.Contacts[ev.Data[event.RemotePeer]].State = ev.Data[event.ConnectionState]
  217. }
  218. case event.ServerStateChange:
  219. for _, group := range ps.profile.Groups {
  220. if group.GroupServer == ev.Data[event.GroupServer] {
  221. group.State = ev.Data[event.ConnectionState]
  222. }
  223. }
  224. case event.DeleteContact:
  225. onion := ev.Data[event.RemotePeer]
  226. ps.profile.DeleteContact(onion)
  227. ps.save()
  228. case event.DeleteGroup:
  229. groupID := ev.Data[event.GroupID]
  230. ps.profile.DeleteGroup(groupID)
  231. ps.save()
  232. ss, exists := ps.streamStores[groupID]
  233. if exists {
  234. ss.Delete()
  235. delete(ps.streamStores, groupID)
  236. }
  237. default:
  238. return
  239. }
  240. }
  241. }
  242. func (ps *profileStore) Shutdown() {
  243. if ps.queue != nil {
  244. ps.queue.Shutdown()
  245. }
  246. }