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.

490 lines
14KB

  1. package model
  2. import (
  3. "crypto/rand"
  4. "cwtch.im/cwtch/protocol"
  5. "encoding/base32"
  6. "encoding/hex"
  7. "encoding/json"
  8. "errors"
  9. "git.openprivacy.ca/openprivacy/connectivity/tor"
  10. "git.openprivacy.ca/openprivacy/libricochet-go/utils"
  11. "github.com/golang/protobuf/proto"
  12. "golang.org/x/crypto/ed25519"
  13. "io"
  14. "path/filepath"
  15. "strings"
  16. "sync"
  17. "time"
  18. )
  19. // PublicProfile is a local copy of a CwtchIdentity
  20. type PublicProfile struct {
  21. Name string
  22. Ed25519PublicKey ed25519.PublicKey
  23. Trusted bool
  24. Blocked bool
  25. Onion string
  26. Attributes map[string]string
  27. Timeline Timeline `json:"-"`
  28. LocalID string // used by storage engine
  29. State string `json:"-"`
  30. lock sync.Mutex
  31. unacknowledgedMessages map[string]Message
  32. }
  33. // Profile encapsulates all the attributes necessary to be a Cwtch Peer.
  34. type Profile struct {
  35. PublicProfile
  36. Contacts map[string]*PublicProfile
  37. Ed25519PrivateKey ed25519.PrivateKey
  38. Groups map[string]*Group
  39. }
  40. // MaxGroupMessageLength is the maximum length of a message posted to a server group.
  41. // TODO: Should this be per server?
  42. const MaxGroupMessageLength = 1800
  43. // GenerateRandomID generates a random 16 byte hex id code
  44. func GenerateRandomID() string {
  45. randBytes := make([]byte, 16)
  46. rand.Read(randBytes)
  47. return filepath.Join(hex.EncodeToString(randBytes))
  48. }
  49. func (p *PublicProfile) init() {
  50. if p.Attributes == nil {
  51. p.Attributes = make(map[string]string)
  52. }
  53. p.unacknowledgedMessages = make(map[string]Message)
  54. p.LocalID = GenerateRandomID()
  55. }
  56. // SetAttribute allows applications to store arbitrary configuration info at the profile level.
  57. func (p *PublicProfile) SetAttribute(name string, value string) {
  58. p.lock.Lock()
  59. defer p.lock.Unlock()
  60. p.Attributes[name] = value
  61. }
  62. // GetAttribute returns the value of a value set with SetCustomAttribute. If no such value has been set exists is set to false.
  63. func (p *PublicProfile) GetAttribute(name string) (value string, exists bool) {
  64. p.lock.Lock()
  65. defer p.lock.Unlock()
  66. value, exists = p.Attributes[name]
  67. return
  68. }
  69. // GenerateNewProfile creates a new profile, with new encryption and signing keys, and a profile name.
  70. func GenerateNewProfile(name string) *Profile {
  71. p := new(Profile)
  72. p.init()
  73. p.Name = name
  74. pub, priv, _ := ed25519.GenerateKey(rand.Reader)
  75. p.Ed25519PublicKey = pub
  76. p.Ed25519PrivateKey = priv
  77. p.Onion = tor.GetTorV3Hostname(pub)
  78. p.Contacts = make(map[string]*PublicProfile)
  79. p.Contacts[p.Onion] = &p.PublicProfile
  80. p.Groups = make(map[string]*Group)
  81. return p
  82. }
  83. // AddContact allows direct manipulation of cwtch contacts
  84. func (p *Profile) AddContact(onion string, profile *PublicProfile) {
  85. p.lock.Lock()
  86. profile.init()
  87. // TODO: More Robust V3 Onion Handling
  88. decodedPub, _ := base32.StdEncoding.DecodeString(strings.ToUpper(onion[:56]))
  89. profile.Ed25519PublicKey = ed25519.PublicKey(decodedPub[:32])
  90. p.Contacts[onion] = profile
  91. p.lock.Unlock()
  92. }
  93. // DeleteContact deletes a peer contact
  94. func (p *Profile) DeleteContact(onion string) {
  95. p.lock.Lock()
  96. defer p.lock.Unlock()
  97. delete(p.Contacts, onion)
  98. }
  99. // DeleteGroup deletes a group
  100. func (p *Profile) DeleteGroup(groupID string) {
  101. p.lock.Lock()
  102. defer p.lock.Unlock()
  103. delete(p.Groups, groupID)
  104. }
  105. // RejectInvite rejects and removes a group invite
  106. func (p *Profile) RejectInvite(groupID string) {
  107. p.lock.Lock()
  108. delete(p.Groups, groupID)
  109. p.lock.Unlock()
  110. }
  111. // AddSentMessageToContactTimeline allows the saving of a message sent via a direct connection chat to the profile.
  112. func (p *Profile) AddSentMessageToContactTimeline(onion string, messageTxt string, sent time.Time, eventID string) *Message {
  113. p.lock.Lock()
  114. defer p.lock.Unlock()
  115. contact, ok := p.Contacts[onion]
  116. if ok {
  117. now := time.Now()
  118. sig := p.SignMessage(onion + messageTxt + sent.String() + now.String())
  119. message := &Message{PeerID: p.Onion, Message: messageTxt, Timestamp: sent, Received: now, Signature: sig, Acknowledged: false}
  120. if contact.unacknowledgedMessages == nil {
  121. contact.unacknowledgedMessages = make(map[string]Message)
  122. }
  123. contact.unacknowledgedMessages[eventID] = *message
  124. return message
  125. }
  126. return nil
  127. }
  128. // AddMessageToContactTimeline allows the saving of a message sent via a direct connection chat to the profile.
  129. func (p *Profile) AddMessageToContactTimeline(onion string, messageTxt string, sent time.Time) (message *Message) {
  130. p.lock.Lock()
  131. defer p.lock.Unlock()
  132. contact, ok := p.Contacts[onion]
  133. // We don't really need a Signature here, but we use it to maintain order
  134. now := time.Now()
  135. sig := p.SignMessage(onion + messageTxt + sent.String() + now.String())
  136. if ok {
  137. message = &Message{PeerID: onion, Message: messageTxt, Timestamp: sent, Received: now, Signature: sig, Acknowledged: true}
  138. contact.Timeline.Insert(message)
  139. }
  140. return
  141. }
  142. // ErrorSentMessageToPeer sets a sent message's error message and removes it from the unacknowledged list
  143. func (p *Profile) ErrorSentMessageToPeer(onion string, eventID string, error string) {
  144. p.lock.Lock()
  145. defer p.lock.Unlock()
  146. contact, ok := p.Contacts[onion]
  147. if ok {
  148. message, ok := contact.unacknowledgedMessages[eventID]
  149. if ok {
  150. message.Error = error
  151. contact.Timeline.Insert(&message) // TODO: do we want a non timeline.Insert way to handle errors
  152. delete(contact.unacknowledgedMessages, eventID)
  153. }
  154. }
  155. }
  156. // AckSentMessageToPeer sets mesage to a peer as acknowledged
  157. func (p *Profile) AckSentMessageToPeer(onion string, eventID string) {
  158. p.lock.Lock()
  159. defer p.lock.Unlock()
  160. contact, ok := p.Contacts[onion]
  161. if ok {
  162. message, ok := contact.unacknowledgedMessages[eventID]
  163. if ok {
  164. message.Acknowledged = true
  165. contact.Timeline.Insert(&message)
  166. delete(contact.unacknowledgedMessages, eventID)
  167. }
  168. }
  169. }
  170. // AddGroupSentMessageError searches matching groups for the message by sig and marks it as an error
  171. func (p *Profile) AddGroupSentMessageError(groupServer string, signature string, error string) {
  172. for _, group := range p.Groups {
  173. if group.GroupServer == groupServer {
  174. if group.ErrorSentMessage([]byte(signature), error) {
  175. break
  176. }
  177. }
  178. }
  179. }
  180. // AcceptInvite accepts a group invite
  181. func (p *Profile) AcceptInvite(groupID string) (err error) {
  182. p.lock.Lock()
  183. defer p.lock.Unlock()
  184. group, ok := p.Groups[groupID]
  185. if ok {
  186. group.Accepted = true
  187. } else {
  188. err = errors.New("group does not exist")
  189. }
  190. return
  191. }
  192. // GetGroups returns an unordered list of group IDs associated with this profile.
  193. func (p *Profile) GetGroups() []string {
  194. p.lock.Lock()
  195. defer p.lock.Unlock()
  196. var keys []string
  197. for onion := range p.Groups {
  198. keys = append(keys, onion)
  199. }
  200. return keys
  201. }
  202. // GetContacts returns an unordered list of contact onions associated with this profile.
  203. func (p *Profile) GetContacts() []string {
  204. p.lock.Lock()
  205. defer p.lock.Unlock()
  206. var keys []string
  207. for onion := range p.Contacts {
  208. if onion != p.Onion {
  209. keys = append(keys, onion)
  210. }
  211. }
  212. return keys
  213. }
  214. // BlockPeer blocks a contact
  215. func (p *Profile) BlockPeer(onion string) (err error) {
  216. p.lock.Lock()
  217. defer p.lock.Unlock()
  218. contact, ok := p.Contacts[onion]
  219. if ok {
  220. contact.Blocked = true
  221. } else {
  222. err = errors.New("peer does not exist")
  223. }
  224. return
  225. }
  226. // UnblockPeer unblocks a contact
  227. func (p *Profile) UnblockPeer(onion string) (err error) {
  228. p.lock.Lock()
  229. defer p.lock.Unlock()
  230. contact, ok := p.Contacts[onion]
  231. if ok {
  232. contact.Blocked = false
  233. } else {
  234. err = errors.New("peer does not exist")
  235. }
  236. return
  237. }
  238. // BlockedPeers calculates a list of Peers who have been Blocked.
  239. func (p *Profile) BlockedPeers() []string {
  240. blockedPeers := []string{}
  241. for _, contact := range p.GetContacts() {
  242. c, _ := p.GetContact(contact)
  243. if c.Blocked {
  244. blockedPeers = append(blockedPeers, c.Onion)
  245. }
  246. }
  247. return blockedPeers
  248. }
  249. // TrustPeer sets a contact to trusted
  250. func (p *Profile) TrustPeer(onion string) (err error) {
  251. p.lock.Lock()
  252. defer p.lock.Unlock()
  253. contact, ok := p.Contacts[onion]
  254. if ok {
  255. contact.Trusted = true
  256. } else {
  257. err = errors.New("peer does not exist")
  258. }
  259. return
  260. }
  261. // IsBlocked returns true if the contact has been blocked, false otherwise
  262. func (p *Profile) IsBlocked(onion string) bool {
  263. contact, ok := p.GetContact(onion)
  264. if ok {
  265. return contact.Blocked
  266. }
  267. return false
  268. }
  269. // GetContact returns a contact if the profile has it
  270. func (p *Profile) GetContact(onion string) (*PublicProfile, bool) {
  271. p.lock.Lock()
  272. defer p.lock.Unlock()
  273. contact, ok := p.Contacts[onion]
  274. return contact, ok
  275. }
  276. // VerifyGroupMessage confirms the authenticity of a message given an onion, message and signature.
  277. func (p *Profile) VerifyGroupMessage(onion string, groupID string, message string, timestamp int32, ciphertext []byte, signature []byte) bool {
  278. group := p.GetGroup(groupID)
  279. if group == nil {
  280. return false
  281. }
  282. if onion == p.Onion {
  283. m := groupID + group.GroupServer + string(ciphertext)
  284. return ed25519.Verify(p.Ed25519PublicKey, []byte(m), signature)
  285. }
  286. m := groupID + group.GroupServer + string(ciphertext)
  287. decodedPub, err := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
  288. if err == nil && len(decodedPub) >= 32 {
  289. return ed25519.Verify(decodedPub[:32], []byte(m), signature)
  290. }
  291. return false
  292. }
  293. // SignMessage takes a given message and returns an Ed21159 signature
  294. func (p *Profile) SignMessage(message string) []byte {
  295. sig := ed25519.Sign(p.Ed25519PrivateKey, []byte(message))
  296. return sig
  297. }
  298. // StartGroup when given a server, creates a new Group under this profile and returns the group id an a precomputed
  299. // invite which can be sent on the wire.
  300. func (p *Profile) StartGroup(server string) (groupID string, invite []byte, err error) {
  301. return p.StartGroupWithMessage(server, []byte{})
  302. }
  303. // StartGroupWithMessage when given a server, and an initial message creates a new Group under this profile and returns the group id an a precomputed
  304. // invite which can be sent on the wire.
  305. func (p *Profile) StartGroupWithMessage(server string, initialMessage []byte) (groupID string, invite []byte, err error) {
  306. group, err := NewGroup(server)
  307. if err != nil {
  308. return "", nil, err
  309. }
  310. groupID = group.GroupID
  311. group.Owner = p.Onion
  312. signedGroupID := p.SignMessage(groupID + server)
  313. group.SignGroup(signedGroupID)
  314. invite, err = group.Invite(initialMessage)
  315. p.lock.Lock()
  316. defer p.lock.Unlock()
  317. p.Groups[group.GroupID] = group
  318. return
  319. }
  320. // GetGroup a pointer to a Group by the group Id, returns nil if no group found.
  321. func (p *Profile) GetGroup(groupID string) (g *Group) {
  322. p.lock.Lock()
  323. defer p.lock.Unlock()
  324. g = p.Groups[groupID]
  325. return
  326. }
  327. // ProcessInvite adds a new group invite to the profile. returns the new group ID
  328. func (p *Profile) ProcessInvite(invite string, peerHostname string) (string, error) {
  329. var gci protocol.GroupChatInvite
  330. err := proto.Unmarshal([]byte(invite), &gci)
  331. if err == nil {
  332. group := new(Group)
  333. group.GroupID = gci.GetGroupName()
  334. group.LocalID = GenerateRandomID()
  335. group.SignedGroupID = gci.GetSignedGroupId()
  336. copy(group.GroupKey[:], gci.GetGroupSharedKey()[:])
  337. group.GroupServer = gci.GetServerHost()
  338. group.InitialMessage = gci.GetInitialMessage()[:]
  339. group.Accepted = false
  340. group.Owner = peerHostname
  341. group.Attributes = make(map[string]string)
  342. p.AddGroup(group)
  343. return group.GroupID, nil
  344. }
  345. return "", err
  346. }
  347. // AddGroup is a convenience method for adding a group to a profile.
  348. func (p *Profile) AddGroup(group *Group) {
  349. _, exists := p.Groups[group.GroupID]
  350. if !exists {
  351. p.lock.Lock()
  352. defer p.lock.Unlock()
  353. p.Groups[group.GroupID] = group
  354. }
  355. }
  356. // AttemptDecryption takes a ciphertext and signature and attempts to decrypt it under known groups.
  357. // If successful, adds the message to the group's timeline
  358. func (p *Profile) AttemptDecryption(ciphertext []byte, signature []byte) (bool, string, *Message, bool) {
  359. for _, group := range p.Groups {
  360. success, dgm := group.DecryptMessage(ciphertext)
  361. if success {
  362. verified := p.VerifyGroupMessage(dgm.GetOnion(), group.GroupID, dgm.GetText(), dgm.GetTimestamp(), ciphertext, signature)
  363. // So we have a message that has a valid group key, but the signature can't be verified.
  364. // The most obvious explanation for this is that the group key has been compromised (or we are in an open group and the server is being malicious)
  365. // Either way, someone who has the private key is being detectably bad so we are just going to throw this message away and mark the group as Compromised.
  366. if !verified {
  367. group.Compromised()
  368. return false, group.GroupID, nil, false
  369. }
  370. message, seen := group.AddMessage(dgm, signature)
  371. return true, group.GroupID, message, seen
  372. }
  373. }
  374. // If we couldn't find a group to decrypt the message with we just return false. This is an expected case
  375. return false, "", nil, false
  376. }
  377. func getRandomness(arr *[]byte) {
  378. if _, err := io.ReadFull(rand.Reader, (*arr)[:]); err != nil {
  379. utils.CheckError(err)
  380. }
  381. }
  382. // EncryptMessageToGroup when given a message and a group, encrypts and signs the message under the group and
  383. // profile
  384. func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, []byte, error) {
  385. if len(message) > MaxGroupMessageLength {
  386. return nil, nil, errors.New("group message is too long")
  387. }
  388. group := p.GetGroup(groupID)
  389. if group != nil {
  390. timestamp := time.Now().Unix()
  391. var prevSig []byte
  392. if len(group.Timeline.Messages) > 0 {
  393. prevSig = group.Timeline.Messages[len(group.Timeline.Messages)-1].Signature
  394. } else {
  395. prevSig = group.SignedGroupID
  396. }
  397. lenPadding := MaxGroupMessageLength - len(message)
  398. padding := make([]byte, lenPadding)
  399. getRandomness(&padding)
  400. dm := &protocol.DecryptedGroupMessage{
  401. Onion: proto.String(p.Onion),
  402. Text: proto.String(message),
  403. SignedGroupId: group.SignedGroupID[:],
  404. Timestamp: proto.Int32(int32(timestamp)),
  405. PreviousMessageSig: prevSig,
  406. Padding: padding[:],
  407. }
  408. ciphertext, err := group.EncryptMessage(dm)
  409. if err != nil {
  410. return nil, nil, err
  411. }
  412. signature := p.SignMessage(groupID + group.GroupServer + string(ciphertext))
  413. group.AddSentMessage(dm, signature)
  414. return ciphertext, signature, nil
  415. }
  416. return nil, nil, errors.New("group does not exist")
  417. }
  418. // GetCopy returns a full deep copy of the Profile struct and its members (timeline inclusion control by arg)
  419. func (p *Profile) GetCopy(timeline bool) *Profile {
  420. p.lock.Lock()
  421. defer p.lock.Unlock()
  422. newp := new(Profile)
  423. bytes, _ := json.Marshal(p)
  424. json.Unmarshal(bytes, &newp)
  425. if timeline {
  426. for groupID := range newp.Groups {
  427. newp.Groups[groupID].Timeline = *p.Groups[groupID].Timeline.GetCopy()
  428. }
  429. }
  430. return newp
  431. }