diff --git a/channels/emoji.go b/channels/emoji.go index f97d50889ccb3f931ee33b22f970b5b8747b9465..d65844745e2c81ea549a962a81999fefc09e7214 100644 --- a/channels/emoji.go +++ b/channels/emoji.go @@ -1,6 +1,22 @@ package channels +import ( + "github.com/forPelevin/gomoji" + "github.com/pkg/errors" +) + +var InvalidReaction = errors.New("The reaction is not valid, " + + "it must be a single emoji") + // ValidateReaction checks that the reaction only contains a single Emoji func ValidateReaction(reaction string) error { + if len(gomoji.RemoveEmojis(reaction)) > 0 { + return InvalidReaction + } + + if len(gomoji.FindAll(reaction)) != 1 { + return InvalidReaction + } + return nil } diff --git a/channels/eventModel.go b/channels/eventModel.go index 08eb972610026dfd8770aabe55fa5f0f01e078ca..93841ba39764e6fe9e608070f1fda363c781e0dc 100644 --- a/channels/eventModel.go +++ b/channels/eventModel.go @@ -36,7 +36,7 @@ type EventModel interface { round rounds.Round) ReceiveReaction(ChannelID *id.ID, MessageID cryptoChannel.MessageID, ReactionTo cryptoChannel.MessageID, SenderUsername string, - Reaction []byte, timestamp time.Time, lease time.Duration, + Reaction string, timestamp time.Time, lease time.Duration, round rounds.Round) //unimplemented @@ -67,7 +67,7 @@ func initEvents(model EventModel) *events { //set up default message types e.registered[Text] = e.receiveTextMessage e.registered[AdminText] = e.receiveTextMessage - e.registered[Reaction] = + e.registered[Reaction] = e.receiveReaction return e } @@ -178,22 +178,25 @@ func (e *events) receiveReaction(ChannelID *id.ID, return } + //check that the reaction is a single emoji and ignore if it isn't + if err := ValidateReaction(react.Reaction); err != nil { + jww.ERROR.Printf("Failed process reaction %s from %s on channel "+ + "%s, type %s, ts: %s, lease: %s, round: %d, due to malformed "+ + "reaction (%s), ignoring reaction", + MessageID, SenderUsername, ChannelID, messageType, timestamp, lease, + round.ID, err) + } + if react.ReactionMessageID != nil && len(react.ReactionMessageID) == cryptoChannel.MessageIDLen { var reactTo cryptoChannel.MessageID - copy(replyTo[:], react.ReactionMessageID) - e.model.ReceiveReply(ChannelID, MessageID, replyTo, SenderUsername, txt.Text, - timestamp, lease, round) - return - + copy(reactTo[:], react.ReactionMessageID) + e.model.ReceiveReaction(ChannelID, MessageID, reactTo, SenderUsername, + react.Reaction, timestamp, lease, round) } else { - jww.ERROR.Printf("Failed process reply to for message %s from %s on "+ - "channel %s, type %s, ts: %s, lease: %s, round: %d, returning "+ - "without reply", + jww.ERROR.Printf("Failed process reaction %s from %s on channel "+ + "%s, type %s, ts: %s, lease: %s, round: %d, reacting to "+ + "invalid message, ignoring reaction", MessageID, SenderUsername, ChannelID, messageType, timestamp, lease, round.ID) } } - -e.model.ReceiveMessage(ChannelID, MessageID, SenderUsername, txt.Text, -timestamp, lease, round) -} \ No newline at end of file diff --git a/channels/joinedChannel.go b/channels/joinedChannel.go index 81c34bb4884fab649b68c69f95e833c648947797..0496298d6136b771a1cd53b2342ef180bafb4e2f 100644 --- a/channels/joinedChannel.go +++ b/channels/joinedChannel.go @@ -48,11 +48,14 @@ func (m *manager) storeUnsafe() error { // loadChannels loads all currently joined channels from disk and registers // them for message reception -func (m *manager) loadChannels() map[*id.ID]*joinedChannel { +func (m *manager) loadChannels() { obj, err := m.kv.Get(joinedChannelsKey, joinedChannelsVersion) - if err != nil { + if !m.kv.Exists(err) { + m.channels = make(map[*id.ID]*joinedChannel) + return + } else if err != nil { jww.FATAL.Panicf("Failed to load channels %+v", err) } @@ -72,7 +75,8 @@ func (m *manager) loadChannels() map[*id.ID]*joinedChannel { } chMap[chList[i]] = jc } - return chMap + + m.channels = chMap } //addChannel Adds a channel diff --git a/channels/manager.go b/channels/manager.go index bf8f820b671f9dfa4d4fc83bb753eff56a599b28..ebad0194c14b4bece68862b8a26746e33620459e 100644 --- a/channels/manager.go +++ b/channels/manager.go @@ -22,11 +22,30 @@ type manager struct { //Events model events + + // make the function used to create broadcasts be a pointer so it + // can be replaced in tests broadcastMaker broadcast.NewBroadcastChannelFunc } -func NewManager() { +func NewManager(kv *versioned.KV, client broadcast.Client, + rng *fastRNG.StreamGenerator, name NameService) Manager { + + //prefix the kv with the username so multiple can be run + kv = kv.Prefix(name.GetUsername()) + + m := manager{ + kv: kv, + client: client, + rng: rng, + name: name, + events: events{}, + broadcastMaker: broadcast.NewBroadcastChannel, + } + + m.loadChannels() + return &m } func (m *manager) JoinChannel(channel cryptoBroadcast.Channel) error { diff --git a/channels/send.go b/channels/send.go index 34dfeef454c1fb1484741553ddf30ae38915d76d..86b34441aabd3e6a3d9a657cad2a177ae542b07d 100644 --- a/channels/send.go +++ b/channels/send.go @@ -1,7 +1,6 @@ package channels import ( - "github.com/forPelevin/gomoji" "gitlab.com/elixxir/client/broadcast" "gitlab.com/elixxir/client/cmix" cryptoChannel "gitlab.com/elixxir/crypto/channel" @@ -17,9 +16,9 @@ const ( cmixChannelReactionVersion = 0 ) -func (m *manager) SendGeneric(channelID *id.ID, msg []byte, validUntil time.Duration, - messageType MessageType, params cmix.CMIXParams) (cryptoChannel.MessageID, - id.Round, ephemeral.Id, error) { +func (m *manager) SendGeneric(channelID *id.ID, messageType MessageType, + msg []byte, validUntil time.Duration, params cmix.CMIXParams) ( + cryptoChannel.MessageID, id.Round, ephemeral.Id, error) { //find the channel ch, err := m.getChannel(channelID) @@ -160,7 +159,7 @@ func (m *manager) SendMessage(channelID *id.ID, msg string, return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err } - return m.SendGeneric(channelID, txtMarshaled, validUntil, Text, params) + return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params) } func (m *manager) SendReply(channelID *id.ID, msg string, @@ -178,7 +177,7 @@ func (m *manager) SendReply(channelID *id.ID, msg string, return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err } - return m.SendGeneric(channelID, txtMarshaled, validUntil, Text, params) + return m.SendGeneric(channelID, Text, txtMarshaled, validUntil, params) } func (m *manager) SendReaction(channelID *id.ID, reaction string, @@ -186,20 +185,20 @@ func (m *manager) SendReaction(channelID *id.ID, reaction string, params cmix.CMIXParams) (cryptoChannel.MessageID, id.Round, ephemeral.Id, error) { - if len(reaction) != 1 { - return error + if err := ValidateReaction(reaction); err != nil { + return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err } - txt := &CMIXChannelReaction{ + react := &CMIXChannelReaction{ Version: cmixChannelReactionVersion, Reaction: reaction, ReactionMessageID: replyTo[:], } - txtMarshaled, err := proto.Marshal(txt) + reactMarshaled, err := proto.Marshal(react) if err != nil { return cryptoChannel.MessageID{}, 0, ephemeral.Id{}, err } - return m.SendGeneric(channelID, txtMarshaled, validUntil, Text, params) + return m.SendGeneric(channelID, Reaction, reactMarshaled, validUntil, params) } diff --git a/channels/text.pb.go b/channels/text.pb.go index ebada41edb208d4e5534f55a96831dedd407bd06..20dcb07ee9307c6d66aeaa3b5b5f118fc96d439b 100644 --- a/channels/text.pb.go +++ b/channels/text.pb.go @@ -96,7 +96,7 @@ type CMIXChannelReaction struct { unknownFields protoimpl.UnknownFields Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` - Reaction uint32 `protobuf:"varint,2,opt,name=reaction,proto3" json:"reaction,omitempty"` + Reaction string `protobuf:"bytes,2,opt,name=reaction,proto3" json:"reaction,omitempty"` ReactionMessageID []byte `protobuf:"bytes,3,opt,name=reactionMessageID,proto3" json:"reactionMessageID,omitempty"` } @@ -139,11 +139,11 @@ func (x *CMIXChannelReaction) GetVersion() uint32 { return 0 } -func (x *CMIXChannelReaction) GetReaction() uint32 { +func (x *CMIXChannelReaction) GetReaction() string { if x != nil { return x.Reaction } - return 0 + return "" } func (x *CMIXChannelReaction) GetReactionMessageID() []byte { @@ -167,7 +167,7 @@ var file_text_proto_rawDesc = []byte{ 0x43, 0x4d, 0x49, 0x58, 0x43, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x11, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, diff --git a/channels/text.proto b/channels/text.proto index 4e1ad86791428f0d64e92b5bbb1d35d7b02567c4..c2d15310a23b0f293af9f3f2cad7e07332269290 100644 --- a/channels/text.proto +++ b/channels/text.proto @@ -18,6 +18,6 @@ message CMIXChannelText { message CMIXChannelReaction { uint32 version = 1; - uint32 reaction = 2; + string reaction = 2; bytes reactionMessageID = 3; } \ No newline at end of file