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.

profile_store.go 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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() *model.Profile
  28. }
  29. // NewProfileWriterStore returns a profile store backed by a filestore listening for events and saving them
  30. // directory should be $appDir/profiles/$rand
  31. func NewProfileWriterStore(eventManager event.Manager, directory, password string, profile *model.Profile) ProfileStore {
  32. os.Mkdir(directory, 0700)
  33. ps := &profileStore{fs: NewFileStore(directory, profileFilename, password), password: password, directory: directory, profile: profile, eventManager: eventManager, streamStores: map[string]StreamStore{}, writer: true}
  34. ps.queue = event.NewEventQueue(100)
  35. if profile != nil {
  36. ps.save()
  37. }
  38. go ps.eventHandler()
  39. ps.eventManager.Subscribe(event.BlockPeer, ps.queue.EventChannel)
  40. ps.eventManager.Subscribe(event.PeerCreated, ps.queue.EventChannel)
  41. ps.eventManager.Subscribe(event.GroupCreated, ps.queue.EventChannel)
  42. ps.eventManager.Subscribe(event.SetProfileName, ps.queue.EventChannel)
  43. ps.eventManager.Subscribe(event.SetAttribute, ps.queue.EventChannel)
  44. ps.eventManager.Subscribe(event.SetPeerAttribute, ps.queue.EventChannel)
  45. ps.eventManager.Subscribe(event.SetGroupAttribute, ps.queue.EventChannel)
  46. ps.eventManager.Subscribe(event.AcceptGroupInvite, ps.queue.EventChannel)
  47. ps.eventManager.Subscribe(event.NewGroupInvite, ps.queue.EventChannel)
  48. ps.eventManager.Subscribe(event.NewMessageFromGroup, ps.queue.EventChannel)
  49. return ps
  50. }
  51. // ReadProfile reads a profile from storqage and returns the profile
  52. // directory should be $appDir/profiles/$rand
  53. func ReadProfile(directory, password string) (*model.Profile, error) {
  54. os.Mkdir(directory, 0700)
  55. ps := &profileStore{fs: NewFileStore(directory, profileFilename, password), password: password, directory: directory, profile: nil, eventManager: nil, streamStores: map[string]StreamStore{}, writer: true}
  56. err := ps.Load()
  57. if err != nil {
  58. return nil, err
  59. }
  60. profile := ps.GetProfileCopy()
  61. return profile, nil
  62. }
  63. // NewProfile creates a new profile for use in the profile store.
  64. func NewProfile(name string) *model.Profile {
  65. profile := model.GenerateNewProfile(name)
  66. return profile
  67. }
  68. func (ps *profileStore) save() error {
  69. if ps.writer {
  70. bytes, _ := json.Marshal(ps.profile)
  71. return ps.fs.Save(bytes)
  72. }
  73. return nil
  74. }
  75. // Load instantiates a cwtchPeer from the file store
  76. func (ps *profileStore) Load() error {
  77. decrypted, err := ps.fs.Load()
  78. if err != nil {
  79. return err
  80. }
  81. cp := new(model.Profile)
  82. err = json.Unmarshal(decrypted, &cp)
  83. if err == nil {
  84. ps.profile = cp
  85. for _, profile := range cp.Contacts {
  86. ss := NewStreamStore(ps.directory, profile.LocalID, ps.password)
  87. profile.Timeline.SetMessages(ss.Read())
  88. ps.streamStores[profile.Onion] = ss
  89. }
  90. for _, group := range cp.Groups {
  91. ss := NewStreamStore(ps.directory, group.LocalID, ps.password)
  92. group.Timeline.SetMessages(ss.Read())
  93. ps.streamStores[group.GroupID] = ss
  94. }
  95. }
  96. return err
  97. }
  98. func (ps *profileStore) GetProfileCopy() *model.Profile {
  99. return ps.profile.GetCopy()
  100. }
  101. func (ps *profileStore) eventHandler() {
  102. for {
  103. ev := ps.queue.Next()
  104. switch ev.EventType {
  105. case event.BlockPeer:
  106. contact, exists := ps.profile.GetContact(ev.Data["Onion"])
  107. if exists {
  108. contact.Blocked = true
  109. ps.save()
  110. }
  111. case event.PeerCreated:
  112. var pp *model.PublicProfile
  113. json.Unmarshal([]byte(ev.Data[event.Data]), &pp)
  114. ps.profile.AddContact(ev.Data[event.RemotePeer], pp)
  115. ss := NewStreamStore(ps.directory, pp.LocalID, ps.password)
  116. pp.Timeline.SetMessages(ss.Read())
  117. ps.streamStores[pp.Onion] = ss
  118. ps.save()
  119. case event.GroupCreated:
  120. var group *model.Group
  121. json.Unmarshal([]byte(ev.Data[event.Data]), &group)
  122. ps.profile.AddGroup(group)
  123. ps.streamStores[group.GroupID] = NewStreamStore(ps.directory, group.LocalID, ps.password)
  124. ps.save()
  125. case event.SetProfileName:
  126. ps.profile.Name = ev.Data[event.ProfileName]
  127. ps.profile.SetAttribute("name", ev.Data[event.ProfileName])
  128. ps.save()
  129. case event.SetAttribute:
  130. ps.profile.SetAttribute(ev.Data[event.Key], ev.Data[event.Data])
  131. ps.save()
  132. case event.SetPeerAttribute:
  133. contact, exists := ps.profile.GetContact(ev.Data[event.RemotePeer])
  134. if exists {
  135. contact.SetAttribute(ev.Data[event.Key], ev.Data[event.Data])
  136. ps.save()
  137. } else {
  138. log.Errorf("error setting attribute on peer %v peer does not exist", ev)
  139. }
  140. case event.SetGroupAttribute:
  141. group := ps.profile.GetGroupByGroupID(ev.Data[event.GroupID])
  142. if group != nil {
  143. group.SetAttribute(ev.Data[event.Key], ev.Data[event.Data])
  144. ps.save()
  145. } else {
  146. log.Errorf("error setting attribute on group %v group does not exist", ev)
  147. }
  148. case event.AcceptGroupInvite:
  149. err := ps.profile.AcceptInvite(ev.Data[event.GroupID])
  150. if err == nil {
  151. ps.save()
  152. } else {
  153. log.Errorf("error accepting group invite")
  154. }
  155. case event.NewGroupInvite:
  156. var gci protocol.GroupChatInvite
  157. err := proto.Unmarshal([]byte(ev.Data[event.GroupInvite]), &gci)
  158. if err == nil {
  159. ps.profile.ProcessInvite(&gci, ev.Data[event.RemotePeer])
  160. ps.save()
  161. group := ps.profile.Groups[gci.GetGroupName()]
  162. ps.streamStores[group.GroupID] = NewStreamStore(ps.directory, group.LocalID, ps.password)
  163. } else {
  164. log.Errorf("error storing new group invite: %v %v", ev, err)
  165. }
  166. case event.NewMessageFromGroup:
  167. groupid := ev.Data[event.GroupID]
  168. received, _ := time.Parse(time.RFC3339Nano, ev.Data[event.TimestampReceived])
  169. sent, _ := time.Parse(time.RFC3339Nano, ev.Data[event.TimestampSent])
  170. 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])}
  171. ss, exists := ps.streamStores[groupid]
  172. if exists {
  173. ss.Write(message)
  174. } else {
  175. log.Errorf("error storing new group message: %v stream store does not exist", ev)
  176. }
  177. default:
  178. return
  179. }
  180. }
  181. }
  182. func (ps *profileStore) Shutdown() {
  183. if ps.queue != nil {
  184. ps.queue.Shutdown()
  185. }
  186. }