go-ricochet/channels/contactrequestchannel.go

149 lines
5.0 KiB
Go

package channels
import (
"errors"
"github.com/golang/protobuf/proto"
"github.com/s-rah/go-ricochet/utils"
"github.com/s-rah/go-ricochet/wire/contact"
"github.com/s-rah/go-ricochet/wire/control"
)
// ContactRequestChannel implements the ChannelHandler interface for a channel of
// type "im.ricochet.contact.request". The channel may be inbound or outbound.
// a ContactRequestChannelHandler implementation to handle chat events.
type ContactRequestChannel struct {
// Methods of Handler are called for chat events on this channel
Handler ContactRequestChannelHandler
channel *Channel
}
// ContactRequestChannelHandler is implemented by an application type to receive
// events from a ContactRequestChannel.
//
// Note that ContactRequestChannelHandler is composable with other interfaces, including
// ConnectionHandler; there is no need to use a distinct type as a
// ContactRequestChannelHandler.
type ContactRequestChannelHandler interface {
GetContactDetails() (string, string)
ContactRequest(name string, message string) string
ContactRequestRejected()
ContactRequestAccepted()
ContactRequestError()
}
// OnlyClientCanOpen - only clients can open contact requests
func (crc *ContactRequestChannel) OnlyClientCanOpen() bool {
return true
}
// Singleton - only one contact request can be opened per side
func (crc *ContactRequestChannel) Singleton() bool {
return true
}
// Bidirectional - only clients can send messages
func (crc *ContactRequestChannel) Bidirectional() bool {
return false
}
// RequiresAuthentication - contact requests require hidden service auth
func (crc *ContactRequestChannel) RequiresAuthentication() string {
return "im.ricochet.auth.hidden-service"
}
// Type returns the type string for this channel, e.g. "im.ricochet.chat".
func (crc *ContactRequestChannel) Type() string {
return "im.ricochet.contact.request"
}
// Closed is called when the channel is closed for any reason.
func (crc *ContactRequestChannel) Closed(err error) {
}
// OpenInbound is the first method called for an inbound channel request.
// If an error is returned, the channel is rejected. If a RawMessage is
// returned, it will be sent as the ChannelResult message.
func (crc *ContactRequestChannel) OpenInbound(channel *Channel, oc *Protocol_Data_Control.OpenChannel) ([]byte, error) {
crc.channel = channel
contactRequestI, err := proto.GetExtension(oc, Protocol_Data_ContactRequest.E_ContactRequest)
if err == nil {
contactRequest, check := contactRequestI.(*Protocol_Data_ContactRequest.ContactRequest)
if check {
if len(contactRequest.GetNickname()) > int(Protocol_Data_ContactRequest.Limits_NicknameMaxCharacters) {
// Violation of the Protocol
return nil, errors.New("invalid nickname")
}
if len(contactRequest.GetMessageText()) > int(Protocol_Data_ContactRequest.Limits_MessageMaxCharacters) {
// Violation of the Protocol
return nil, errors.New("invalid message")
}
result := crc.Handler.ContactRequest(contactRequest.GetNickname(), contactRequest.GetMessageText())
messageBuilder := new(utils.MessageBuilder)
return messageBuilder.ReplyToContactRequestOnResponse(channel.ID, result), nil
}
}
return nil, errors.New("could not parse contact request extension")
}
// OpenOutbound is the first method called for an outbound channel request.
// If an error is returned, the channel is not opened. If a RawMessage is
// returned, it will be sent as the OpenChannel message.
func (crc *ContactRequestChannel) OpenOutbound(channel *Channel) ([]byte, error) {
crc.channel = channel
name, message := crc.Handler.GetContactDetails()
messageBuilder := new(utils.MessageBuilder)
return messageBuilder.OpenContactRequestChannel(channel.ID, name, message), nil
}
// OpenOutboundResult is called when a response is received for an
// outbound OpenChannel request. If `err` is non-nil, the channel was
// rejected and Closed will be called immediately afterwards. `raw`
// contains the raw protocol message including any extension data.
func (crc *ContactRequestChannel) OpenOutboundResult(err error, crm *Protocol_Data_Control.ChannelResult) {
if err == nil {
if crm.GetOpened() {
responseI, err := proto.GetExtension(crm, Protocol_Data_ContactRequest.E_Response)
if err == nil {
response, check := responseI.(*Protocol_Data_ContactRequest.Response)
if check {
crc.handleStatus(response.GetStatus().String())
return
}
}
}
}
crc.channel.SendMessage([]byte{})
}
func (crc *ContactRequestChannel) handleStatus(status string) {
switch status {
case "Accepted":
crc.Handler.ContactRequestAccepted()
case "Pending":
break
case "Rejected":
crc.Handler.ContactRequestRejected()
break
case "Error":
crc.Handler.ContactRequestError()
break
}
}
// Packet is called for each raw packet received on this channel.
func (crc *ContactRequestChannel) Packet(data []byte) {
if !crc.channel.Pending {
response := new(Protocol_Data_ContactRequest.Response)
err := proto.Unmarshal(data, response)
if err == nil {
crc.handleStatus(response.GetStatus().String())
return
}
}
crc.channel.SendMessage([]byte{})
}