Official cwtch.im peer and server implementations.
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.

group.go 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package model
  2. import (
  3. "crypto/rand"
  4. "fmt"
  5. "git.mascherari.press/cwtch/protocol"
  6. "github.com/golang/protobuf/proto"
  7. "github.com/s-rah/go-ricochet/utils"
  8. "golang.org/x/crypto/nacl/secretbox"
  9. "io"
  10. "log"
  11. "time"
  12. )
  13. //Group defines and encapsulates Cwtch's conception of group chat. Which are sessions
  14. // tied to a server under a given group key. Each group has a set of messages.
  15. type Group struct {
  16. GroupID string
  17. SignedGroupID []byte
  18. GroupKey [32]byte
  19. GroupServer string
  20. Timeline []Message
  21. Accepted bool
  22. Owner string
  23. }
  24. // NewGroup initializes a new group associated with a given CwtchServer
  25. func NewGroup(server string) *Group {
  26. group := new(Group)
  27. group.GroupServer = server
  28. var groupID [16]byte
  29. if _, err := io.ReadFull(rand.Reader, groupID[:]); err != nil {
  30. panic(err)
  31. }
  32. group.GroupID = fmt.Sprintf("%x", groupID)
  33. var groupKey [32]byte
  34. if _, err := io.ReadFull(rand.Reader, groupKey[:]); err != nil {
  35. panic(err)
  36. }
  37. copy(group.GroupKey[:], groupKey[:])
  38. group.Owner = "self"
  39. return group
  40. }
  41. func (g *Group) SignGroup(signature []byte) {
  42. g.SignedGroupID = signature
  43. }
  44. func (g *Group) Invite() []byte {
  45. gci := &protocol.GroupChatInvite{
  46. GroupName: g.GroupID,
  47. GroupSharedKey: g.GroupKey[:],
  48. ServerHost: g.GroupServer,
  49. SignedGroupId: g.SignedGroupID[:],
  50. }
  51. log.Printf("INVITEBEFORE %v", gci)
  52. cp := &protocol.CwtchPeerPacket{
  53. GroupChatInvite: gci,
  54. }
  55. invite, err := proto.Marshal(cp)
  56. utils.CheckError(err)
  57. return invite
  58. }
  59. func (g *Group) AddMessage(message *protocol.DecryptedGroupMessage, verified bool) {
  60. timelineMessage := Message{
  61. Message: message.GetText(),
  62. Timestamp: time.Unix(int64(message.GetTimestamp()), 0),
  63. Signature: message.GetSignature(),
  64. Verified: verified,
  65. PeerID: message.GetOnion(),
  66. }
  67. g.Timeline = append(g.Timeline, timelineMessage)
  68. }
  69. // AddMember ...
  70. func (g *Group) AddMember() {
  71. // TODO: Rotate Key
  72. }
  73. // RemoveMember ...
  74. func (g *Group) RemoveMember() {
  75. // TODO: Rotate Key
  76. }
  77. //EncryptMessage takes a message and encrypts the message under the group key.
  78. func (g *Group) EncryptMessage(message *protocol.DecryptedGroupMessage) []byte {
  79. var nonce [24]byte
  80. if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil {
  81. panic(err)
  82. }
  83. wire, err := proto.Marshal(message)
  84. utils.CheckError(err)
  85. encrypted := secretbox.Seal(nonce[:], []byte(wire), &nonce, &g.GroupKey)
  86. return encrypted
  87. }
  88. // DecryptMessage takes a ciphertext and returns true and the decrypted message if the
  89. // cipher text can be successfully decrypted,else false.
  90. func (g *Group) DecryptMessage(ciphertext []byte) (bool, *protocol.DecryptedGroupMessage) {
  91. var decryptNonce [24]byte
  92. copy(decryptNonce[:], ciphertext[:24])
  93. decrypted, ok := secretbox.Open(nil, ciphertext[24:], &decryptNonce, &g.GroupKey)
  94. if ok {
  95. dm := &protocol.DecryptedGroupMessage{}
  96. err := proto.Unmarshal(decrypted, dm)
  97. if err == nil {
  98. return true, dm
  99. }
  100. }
  101. return false, nil
  102. }