package send import ( "errors" "git.mascherari.press/cwtch/protocol" "git.mascherari.press/cwtch/protocol/spam" "github.com/golang/protobuf/proto" "github.com/s-rah/go-ricochet/channels" "github.com/s-rah/go-ricochet/utils" "github.com/s-rah/go-ricochet/wire/control" ) // CwtchPeerSendChannel is the peer implementation of im.cwtch.server.send type CwtchPeerSendChannel struct { channel *channels.Channel spamGuard spam.SpamGuard challenge []byte } // Type returns the type string for this channel, e.g. "im.ricochet.server.send". func (cc *CwtchPeerSendChannel) Type() string { return "im.cwtch.server.send" } // Closed is called when the channel is closed for any reason. func (cc *CwtchPeerSendChannel) Closed(err error) { } // OnlyClientCanOpen - for Cwtch server channels only peers may open. func (cc *CwtchPeerSendChannel) OnlyClientCanOpen() bool { return true } // Singleton - for Cwtch channels there can only be one instance per direction func (cc *CwtchPeerSendChannel) Singleton() bool { return true } // Bidirectional - for Cwtch channels are not bidrectional func (cc *CwtchPeerSendChannel) Bidirectional() bool { return false } // RequiresAuthentication - Cwtch channels require no auth func (cc *CwtchPeerSendChannel) RequiresAuthentication() string { return "none" } // OpenInbound should never be called on peers. func (cc *CwtchPeerSendChannel) OpenInbound(channel *channels.Channel, raw *Protocol_Data_Control.OpenChannel) ([]byte, error) { return nil, errors.New("client does not receive inbound listen channels") } // OpenOutbound is used to set up a new send channel and initialize spamguard func (cplc *CwtchPeerSendChannel) OpenOutbound(channel *channels.Channel) ([]byte, error) { cplc.spamGuard.Difficulty = 2 cplc.channel = channel messageBuilder := new(utils.MessageBuilder) return messageBuilder.OpenChannel(channel.ID, cplc.Type()), nil } // OpenOutboundResult confirms the open channel request and sets the spamguard challenge func (cplc *CwtchPeerSendChannel) OpenOutboundResult(err error, crm *Protocol_Data_Control.ChannelResult) { if err == nil { if crm.GetOpened() { cplc.channel.Pending = false ce, _ := proto.GetExtension(crm, protocol.E_ServerNonce) cplc.challenge = ce.([]byte)[:] } } } // SendGroupMessage performs the spamguard proof of work and sends a message. func (cplc *CwtchPeerSendChannel) SendGroupMessage(gm *protocol.GroupMessage) { sgsolve := cplc.spamGuard.SolveChallenge(cplc.challenge, gm.GetCiphertext()) gm.Spamguard = sgsolve[:] csp := &protocol.CwtchServerPacket{ GroupMessage: gm, } packet, _ := proto.Marshal(csp) cplc.channel.SendMessage(packet) } // Packet should never be func (cc *CwtchPeerSendChannel) Packet(data []byte) { // If we receive a packet on this channel, close the connection cc.channel.CloseChannel() }