diff --git a/otr/otr.go b/otr/otr.go index 3e4f350..e4890d5 100644 --- a/otr/otr.go +++ b/otr/otr.go @@ -50,7 +50,11 @@ const ( ) // QueryMessage can be sent to a peer to start an OTR conversation. -var QueryMessage = []byte("?OTRv2?") +var QueryMessage = "?OTRv2?" + +// ErrorPrefix can be used to make an OTR error by appending an error message +// to it. +var ErrorPrefix = "?OTR Error:" var ( fragmentPartSeparator = []byte(",") @@ -398,6 +402,7 @@ func (c *Conversation) Receive(in []byte) (out []byte, encrypted bool, change Se switch inTLV.typ { case tlvTypeDisconnected: change = ConversationEnded + c.state = stateFinished break EachTLV case tlvTypeSMP1, tlvTypeSMP2, tlvTypeSMP3, tlvTypeSMP4, tlvTypeSMPAbort, tlvTypeSMP1WithQuestion: var reply tlv @@ -487,6 +492,22 @@ func (c *Conversation) Authenticate(question string, mutualSecret []byte) (toSen return } +// End ends a secure conversation by generating a termination message for +// the peer and switches to unencrypted communication. +func (c *Conversation) End() (toSend [][]byte) { + switch c.state { + case statePlaintext: + return nil + case stateEncrypted: + c.state = statePlaintext + return c.encode(c.generateData(nil, &tlv{typ: tlvTypeDisconnected})) + case stateFinished: + c.state = statePlaintext + return nil + } + panic("unreachable") +} + var fragmentError = errors.New("otr: invalid OTR fragment") // processFragment processes a fragmented OTR message and possibly returns a