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.
 
 
 
 

476 lines
15 KiB

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