README

OTR3

Build Status Coverage Status

Implements version 3 of the OTR standard. Implements feature parity with libotr 4.1.0.

API Documentation

GoDoc

Developing

Before doing any work, if you want to separate out your GOPATH from other projects, install direnv

$ brew update
$ brew install direnv
$ echo 'eval "$(direnv hook bash)"' >> ~/.bashrc

Then, create a symbolic link to the OTR3 repository

ln -s /PathToMyGoPackages/.gopkgs/otr3/src/github.com/coyim/ .

Install all dependencies:

./deps.sh

Documentation

Overview

Package otr3 implements the Off The Record protocol as specified in:

https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html

Introduction

Off-the-Record (OTR) Messaging allows you to have private conversations over instant messaging by providing:

Encryption
Authentication
Deniability
Perfect forward secrecy

Getting Started

OTR library provides a Conversation API for Receiving and Sending messages

import "otr3"

c := &otr3.Conversation{}

// You will need to prepare a long-term PrivateKey for otr conversation handshakes.
var priv *otr3.DSAPrivateKey
priv.Generate(rand.Reader)
c.SetOurKeys([]otr3.PrivateKey{priv})

// set the Policies.
c.Policies.RequireEncryption()
c.Policies.AllowV2()
c.Policies.AllowV3()
c.Policies.SendWhitespaceTag()
c.Policies.WhitespaceStartAKE()

// You can also setup a debug mode
c.SetDebug(true)

// Use Send and Receive for messages exchange
toSend, err := c.Send(otr3.ValidMessage("hello"))
plain, toSend, err := c.Receive(toSend[0])

// Use Authenticate to start a SMP process
toSend, err := c.StartAuthenticate("My pet's name?",[]byte{"Gopher"})
toSend, err := c.ProvideAuthenticationSecret([]byte{"Gopher"})

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AppendData

func AppendData(l, r []byte) []byte

AppendData will append the serialization of the given value to the byte array Data will be serialized big-endian

func AppendLong

func AppendLong(l []byte, r uint64) []byte

AppendLong will append the serialization of the given value to the byte array Data will be serialized big-endian

func AppendMPI

func AppendMPI(l []byte, r *big.Int) []byte

AppendMPI will append the serialization of the given value to the byte array Data will be serialized big-endian

func AppendMPIs

func AppendMPIs(l []byte, r ...*big.Int) []byte

AppendMPIs will append the serialization of the given values to the byte array Data will be serialized big-endian

func AppendShort

func AppendShort(l []byte, r uint16) []byte

AppendShort will append the serialization of the given value to the byte array Data will be serialized big-endian

func AppendWord

func AppendWord(l []byte, r uint32) []byte

AppendWord will append the serialization of the given value to the byte array Data will be serialized big-endian

func Bytes

func Bytes(m []ValidMessage) [][]byte

Bytes will turn a slice of valid messages into a slice of byte slices

func DeserializeLong

func DeserializeLong(d []byte) uint64

DeserializeLong returns the big endian deserialization of the given value The buffer is expected to be long enough - otherwise a panic will happen

func DeserializeShort

func DeserializeShort(d []byte) uint16

DeserializeShort returns the big endian deserialization of the given value The buffer is expected to be long enough - otherwise a panic will happen

func DeserializeWord

func DeserializeWord(d []byte) uint32

DeserializeWord returns the big endian deserialization of the given value The buffer is expected to be long enough - otherwise a panic will happen

func ExportKeysToFile

func ExportKeysToFile(acs []*Account, fname string) error

ExportKeysToFile will create the named file (or truncate it) and write all the accounts to that file in libotr format.

func ExtractByte

func ExtractByte(d []byte) ([]byte, uint8, bool)

ExtractByte will return the first byte, the rest, and a boolean indicating success Data is expected to be in big-endian format

func ExtractData

func ExtractData(d []byte) (newPoint []byte, data []byte, ok bool)

ExtractData will return the first data, the rest, and a boolean indicating success A Data is serialized as a word indicating length, and then as many bytes as that length Data is expected to be in big-endian format

func ExtractFixedData

func ExtractFixedData(d []byte, l int) (newPoint []byte, data []byte, ok bool)

ExtractFixedData will return the first l bytes, the rest, and a boolean indicating success

func ExtractInstanceTags

func ExtractInstanceTags(m []byte) (ours, theirs uint32, ok bool)

ExtractInstanceTags returns our and theirs instance tags from the message, and ok if the message was parsed properly

func ExtractLong

func ExtractLong(d []byte) ([]byte, uint64, bool)

ExtractLong will return the first long, the rest, and a boolean indicating success Data is expected to be in big-endian format

func ExtractMPI

func ExtractMPI(d []byte) (newPoint []byte, mpi *big.Int, ok bool)

ExtractMPI will return the first MPI, the rest, and a boolean indicating success The MPI is encoded as a word length, followed by length bytes indicating the minimal representation of the MPI in the obvious format. Data is expected to be in big-endian format

func ExtractMPIs

func ExtractMPIs(d []byte) ([]byte, []*big.Int, bool)

ExtractMPIs will return the first len MPIs, the rest, and a boolean indicating success The length is indicated by a word, followed by length MPIs Data is expected to be in big-endian format

func ExtractShort

func ExtractShort(d []byte) ([]byte, uint16, bool)

ExtractShort will return the first short, the rest, and a boolean indicating success Data is expected to be in big-endian format

func ExtractTime

func ExtractTime(d []byte) (newPoint []byte, t time.Time, ok bool)

ExtractTime will return the first time, the rest, and a boolean indicating success Time is encoded as a big-endian 64bit number

func ExtractWord

func ExtractWord(d []byte) ([]byte, uint32, bool)

ExtractWord will return the first word, the rest, and a boolean indicating success Data is expected to be in big-endian format

func SerializeLong

func SerializeLong(r uint64) []byte

SerializeLong returns the big endian serialization of the given value

func SerializeShort

func SerializeShort(r uint16) []byte

SerializeShort returns the big endian serialization of the given value

func SerializeWord

func SerializeWord(r uint32) []byte

SerializeWord returns the big endian serialization of the given value

Types

type Account

type Account struct {
	Name     string
	Protocol string
	Key      PrivateKey
}

Account is a holder for the private key associated with an account It contains name, protocol and otr private key of an otr Account

func ImportKeys

func ImportKeys(r io.Reader) ([]*Account, error)

ImportKeys will read the libotr formatted data given and return all accounts defined in it

func ImportKeysFromFile

func ImportKeysFromFile(fname string) ([]*Account, error)

ImportKeysFromFile will read the libotr formatted file given and return all accounts defined in it

type Conversation

type Conversation struct {
	Rand io.Reader

	Policies policies
	// contains filtered or unexported fields
}

Conversation contains all the information for a specific connection between two peers in an IM system. Policies are not supposed to change once a conversation has been used

func NewConversationWithVersion

func NewConversationWithVersion(v int) *Conversation

NewConversationWithVersion creates a new conversation with the given version

func (*Conversation) AbortAuthentication

func (c *Conversation) AbortAuthentication() ([]ValidMessage, error)

AbortAuthentication should be called when the user wants to abort authentication with a peer. It will return an SMP abort message to send.

func (*Conversation) End

func (c *Conversation) End() (toSend []ValidMessage, err error)

End ends a secure conversation by generating a termination message for the peer and switches to unencrypted communication.

func (*Conversation) GetOurCurrentKey

func (c *Conversation) GetOurCurrentKey() PrivateKey

GetOurCurrentKey returns the currently chosen key for us

func (*Conversation) GetOurInstanceTag

func (c *Conversation) GetOurInstanceTag() uint32

GetOurInstanceTag returns our instance tag - it computes it if none has been computed yet

func (*Conversation) GetOurKeys

func (c *Conversation) GetOurKeys() []PrivateKey

GetOurKeys returns all our keys for the current conversation

func (*Conversation) GetSSID

func (c *Conversation) GetSSID() [8]byte

GetSSID returns the SSID of this Conversation

func (*Conversation) GetTheirInstanceTag

func (c *Conversation) GetTheirInstanceTag() uint32

GetTheirInstanceTag returns the peers instance tag, or 0 if none has been computed yet

func (*Conversation) GetTheirKey

func (c *Conversation) GetTheirKey() PublicKey

GetTheirKey returns the public key of the other peer in this conversation

func (*Conversation) InitializeInstanceTag

func (c *Conversation) InitializeInstanceTag(tag uint32) uint32

InitializeInstanceTag sets our instance tag for this conversation. If the argument is zero we will create a new instance tag and return it The instance tag created or set will be returned

func (*Conversation) IsEncrypted

func (c *Conversation) IsEncrypted() bool

IsEncrypted returns true if the current conversation is private

func (*Conversation) ProvideAuthenticationSecret

func (c *Conversation) ProvideAuthenticationSecret(mutualSecret []byte) ([]ValidMessage, error)

ProvideAuthenticationSecret should be called when the peer has started an authentication request, and the UI has been notified that a secret is needed It is only valid to call this function if the current SMP state is waiting for a secret to be provided. The return is the potential messages to send.

func (*Conversation) QueryMessage

func (c *Conversation) QueryMessage() ValidMessage

QueryMessage will return a QueryMessage determined by Conversation Policies

func (*Conversation) Receive

func (c *Conversation) Receive(m ValidMessage) (plain MessagePlaintext, toSend []ValidMessage, err error)

Receive handles a message from a peer. It returns a human readable message and zero or more messages to send back to the peer.

func (*Conversation) SMPQuestion

func (c *Conversation) SMPQuestion() (string, bool)

SMPQuestion returns the current SMP question and ok if there is one, and not ok if there isn't one.

func (*Conversation) SecureSessionID

func (c *Conversation) SecureSessionID() (parts []string, highlightIndex int)

SecureSessionID returns the secure session ID as two formatted strings The index returned points to the string that should be highlighted

func (*Conversation) Send

func (c *Conversation) Send(m ValidMessage, trace ...interface{}) ([]ValidMessage, error)

Send takes a human readable message from the local user, possibly encrypts it and returns zero or more messages to send to the peer.

func (*Conversation) SetDebug

func (c *Conversation) SetDebug(d bool)

SetDebug sets the debug mode for this conversation. If debug mode is enabled, calls to Send with a message equals to "?OTR!" will dump debug information about the current conversation state to stderr

func (*Conversation) SetErrorMessageHandler

func (c *Conversation) SetErrorMessageHandler(handler ErrorMessageHandler)

SetErrorMessageHandler assigns handler for ErrorMessage

func (*Conversation) SetFragmentSize

func (c *Conversation) SetFragmentSize(size uint16)

SetFragmentSize sets the maximum size for a message fragment. If specified, all messages produced by Receive and Send will be fragmented into messages of, at most, this number of bytes.

func (*Conversation) SetFriendlyQueryMessage

func (c *Conversation) SetFriendlyQueryMessage(msg string)

SetFriendlyQueryMessage will set a new message as query message

func (*Conversation) SetMessageEventHandler

func (c *Conversation) SetMessageEventHandler(handler MessageEventHandler)

SetMessageEventHandler assigns handler for MessageEvent

func (*Conversation) SetOurKeys

func (c *Conversation) SetOurKeys(ourKeys []PrivateKey)

SetOurKeys assigns our private keys to the conversation

func (*Conversation) SetReceivedKeyHandler

func (c *Conversation) SetReceivedKeyHandler(keyHandler ReceivedKeyHandler)

SetReceivedKeyHandler will set the handler for what is to happen when an extra symmetric key is received

func (*Conversation) SetSMPEventHandler

func (c *Conversation) SetSMPEventHandler(handler SMPEventHandler)

SetSMPEventHandler assigns handler for SMPEvent

func (*Conversation) SetSecurityEventHandler

func (c *Conversation) SetSecurityEventHandler(handler SecurityEventHandler)

SetSecurityEventHandler assigns handler for SecurityEvent

func (*Conversation) StartAuthenticate

func (c *Conversation) StartAuthenticate(question string, mutualSecret []byte) ([]ValidMessage, error)

StartAuthenticate should be called when the user wants to initiate authentication with a peer. The authentication uses an optional question message and a shared secret. The authentication will proceed until the event handler reports that SMP is complete, that a secret is needed or that SMP has failed.

func (*Conversation) UseExtraSymmetricKey

func (c *Conversation) UseExtraSymmetricKey(usage uint32, usageData []byte) ([]byte, []ValidMessage, error)

UseExtraSymmetricKey takes a usage parameter and optional usageData and returns the current symmetric key and a set of messages to send in order to ask the peer to use the same symmetric key for the usage defined

type DSAPrivateKey

type DSAPrivateKey struct {
	DSAPublicKey
	dsa.PrivateKey
}

DSAPrivateKey is a DSA private key

func (*DSAPrivateKey) Generate

func (priv *DSAPrivateKey) Generate(rand io.Reader) error

Generate will generate a new DSA Private Key with the randomness provided. The parameter size used is 1024 and 160.

func (*DSAPrivateKey) Import

func (priv *DSAPrivateKey) Import(in []byte) bool

Import parses the contents of a libotr private key file.

func (*DSAPrivateKey) Parse

func (priv *DSAPrivateKey) Parse(in []byte) (index []byte, ok bool)

Parse will parse a Private Key from the given data, by first parsing the public key components and then the private key component. It returns not ok for the same reasons as PublicKey.Parse.

func (*DSAPrivateKey) PublicKey

func (priv *DSAPrivateKey) PublicKey() PublicKey

PublicKey returns the public key corresponding to this private key

func (*DSAPrivateKey) Serialize

func (priv *DSAPrivateKey) Serialize() []byte

Serialize will return the serialization of the private key to a byte array

func (*DSAPrivateKey) Sign

func (priv *DSAPrivateKey) Sign(rand io.Reader, hashed []byte) ([]byte, error)

Sign will generate a signature of a hashed data using dsa Sign.

type DSAPublicKey

type DSAPublicKey struct {
	dsa.PublicKey
}

DSAPublicKey is a DSA public key

func (*DSAPublicKey) Fingerprint

func (pub *DSAPublicKey) Fingerprint() []byte

Fingerprint will generate a fingerprint of the serialized version of the key using the provided hash.

func (*DSAPublicKey) IsAvailableForVersion

func (pub *DSAPublicKey) IsAvailableForVersion(v uint16) bool

IsAvailableForVersion returns true if this key is possible to use with the given version

func (*DSAPublicKey) IsSame

func (pub *DSAPublicKey) IsSame(other PublicKey) bool

IsSame returns true if the given public key is a DSA public key that is equal to this key

func (*DSAPublicKey) Parse

func (pub *DSAPublicKey) Parse(in []byte) (index []byte, ok bool)

Parse takes the given data and tries to parse it into the PublicKey receiver. It will return not ok if the data is malformed or not for a DSA key

func (*DSAPublicKey) Verify

func (pub *DSAPublicKey) Verify(hashed, sig []byte) (nextPoint []byte, sigOk bool)

Verify will verify a signature of a hashed data using dsa Verify.

type DebugErrorMessageHandler

type DebugErrorMessageHandler struct{}

DebugErrorMessageHandler is an ErrorMessageHandler that dumps all error message requests to standard error. It returns nil

func (DebugErrorMessageHandler) HandleErrorMessage

func (DebugErrorMessageHandler) HandleErrorMessage(error ErrorCode) []byte

HandleErrorMessage dumps all error messages and returns nil

type DebugMessageEventHandler

type DebugMessageEventHandler struct{}

DebugMessageEventHandler is a MessageEventHandler that dumps all MessageEvents to standard error

func (DebugMessageEventHandler) HandleMessageEvent

func (DebugMessageEventHandler) HandleMessageEvent(event MessageEvent, message []byte, err error, trace ...interface{})

HandleMessageEvent dumps all message events

type DebugSMPEventHandler

type DebugSMPEventHandler struct{}

DebugSMPEventHandler is an SMPEventHandler that dumps all SMPEvents to standard error

func (DebugSMPEventHandler) HandleSMPEvent

func (DebugSMPEventHandler) HandleSMPEvent(event SMPEvent, progressPercent int, question string)

HandleSMPEvent dumps all SMP events

type DebugSecurityEventHandler

type DebugSecurityEventHandler struct{}

DebugSecurityEventHandler is a SecurityEventHandler that dumps all SecurityEvents to standard error

func (DebugSecurityEventHandler) HandleSecurityEvent

func (DebugSecurityEventHandler) HandleSecurityEvent(event SecurityEvent)

HandleSecurityEvent dumps all security events

type ErrorCode

type ErrorCode int

ErrorCode represents an error that can happen during OTR processing

const (
	// ErrorCodeEncryptionError means an error occured while encrypting a message
	ErrorCodeEncryptionError ErrorCode = iota

	// ErrorCodeMessageUnreadable means we received an unreadable encrypted message
	ErrorCodeMessageUnreadable

	// ErrorCodeMessageMalformed means the message sent is malformed
	ErrorCodeMessageMalformed

	// ErrorCodeMessageNotInPrivate means we received an encrypted message when not expecting it
	ErrorCodeMessageNotInPrivate
)

func (ErrorCode) String

func (s ErrorCode) String() string

type ErrorMessageHandler

type ErrorMessageHandler interface {
	// HandleErrorMessage should return a string according to the error event. This string will be concatenated to an OTR header to produce an OTR protocol error message
	HandleErrorMessage(error ErrorCode) []byte
}

ErrorMessageHandler generates error messages for error codes

func CombineErrorMessageHandlers

func CombineErrorMessageHandlers(handlers ...ErrorMessageHandler) ErrorMessageHandler

CombineErrorMessageHandlers creates an ErrorMessageHandler that will call all handlers given to this function. It returns the result of the final handler called

type MessageEvent

type MessageEvent int

MessageEvent define the events used to indicate the messages that need to be sent

const (
	// MessageEventEncryptionRequired is signaled when our policy requires encryption but we are trying to send an unencrypted message.
	MessageEventEncryptionRequired MessageEvent = iota

	// MessageEventEncryptionError is signaled when an error occured while encrypting a message and the message was not sent.
	MessageEventEncryptionError

	// MessageEventConnectionEnded is signaled when we are asked to send a message but the peer has ended the private conversation.
	// At this point the connection should be closed or refreshed.
	MessageEventConnectionEnded

	// MessageEventSetupError will be signaled when a private conversation could not be established. The reason for this will be communicated with the attached error instance.
	MessageEventSetupError

	// MessageEventMessageReflected will be signaled if we received our own OTR messages.
	MessageEventMessageReflected

	// MessageEventMessageSent is signaled when a message is sent after having been queued
	MessageEventMessageSent

	// MessageEventMessageResent is signaled when a message is resent
	MessageEventMessageResent

	// MessageEventReceivedMessageNotInPrivate will be signaled when we receive an encrypted message that we cannot read, because we don't have an established private connection
	MessageEventReceivedMessageNotInPrivate

	// MessageEventReceivedMessageUnreadable will be signaled when we cannot read the received message.
	MessageEventReceivedMessageUnreadable

	// MessageEventReceivedMessageMalformed is signaled when we receive a message that contains malformed data.
	MessageEventReceivedMessageMalformed

	// MessageEventLogHeartbeatReceived is triggered when we received a heartbeat.
	MessageEventLogHeartbeatReceived

	// MessageEventLogHeartbeatSent is triggered when we have sent a heartbeat.
	MessageEventLogHeartbeatSent

	// MessageEventReceivedMessageGeneralError will be signaled when we receive an OTR error from the peer.
	// The message parameter will be passed, containing the error message
	MessageEventReceivedMessageGeneralError

	// MessageEventReceivedMessageUnencrypted is triggered when we receive a message that was sent in the clear when it should have been encrypted.
	// The actual message received will also be passed.
	MessageEventReceivedMessageUnencrypted

	// MessageEventReceivedMessageUnrecognized is triggered when we receive an OTR message whose type we cannot recognize
	MessageEventReceivedMessageUnrecognized

	// MessageEventReceivedMessageForOtherInstance is triggered when we receive and discard a message for another instance
	MessageEventReceivedMessageForOtherInstance
)

func (MessageEvent) String

func (s MessageEvent) String() string

String returns the string representation of the MessageEvent

type MessageEventHandler

type MessageEventHandler interface {
	// HandleMessageEvent should handle and send the appropriate message(s) to the sender/recipient depending on the message events
	HandleMessageEvent(event MessageEvent, message []byte, err error, trace ...interface{})
}

MessageEventHandler handles MessageEvents

func CombineMessageEventHandlers

func CombineMessageEventHandlers(handlers ...MessageEventHandler) MessageEventHandler

CombineMessageEventHandlers creates a MessageEventHandler that will call all handlers given to this function. It ignores nil entries.

type MessagePlaintext

type MessagePlaintext []byte

MessagePlaintext contains regular plaintext to send or receive

type OtrError

type OtrError struct {
	// contains filtered or unexported fields
}

OtrError is an error in the OTR library

func (OtrError) Error

func (oe OtrError) Error() string

type PrivateKey

type PrivateKey interface {
	Parse([]byte) ([]byte, bool)
	Serialize() []byte
	Sign(io.Reader, []byte) ([]byte, error)
	Generate(io.Reader) error
	PublicKey() PublicKey
	IsAvailableForVersion(uint16) bool
}

PrivateKey is a private key used to sign messages

func GenerateMissingKeys

func GenerateMissingKeys(existing [][]byte) ([]PrivateKey, error)

GenerateMissingKeys will look through the existing serialized keys and generate new keys to ensure that the functioning of this version of OTR will work correctly. It will only return the newly generated keys, not the old ones

func ParsePrivateKey

func ParsePrivateKey(in []byte) (index []byte, ok bool, key PrivateKey)

ParsePrivateKey is an algorithm indepedent way of parsing private keys

type PublicKey

type PublicKey interface {
	Parse([]byte) ([]byte, bool)
	Fingerprint() []byte
	Verify([]byte, []byte) ([]byte, bool)

	IsSame(PublicKey) bool
	// contains filtered or unexported methods
}

PublicKey is a public key used to verify signed messages

func ParsePublicKey

func ParsePublicKey(in []byte) (index []byte, ok bool, key PublicKey)

ParsePublicKey is an algorithm independent way of parsing public keys

type ReceivedKeyHandler

type ReceivedKeyHandler interface {
	// ReceivedSymmetricKey will be called when a TLV requesting the use of a symmetric key is received
	ReceivedSymmetricKey(usage uint32, usageData []byte, symkey []byte)
}

ReceivedKeyHandler is an interface that will be invoked when an extra key is received

type SMPEvent

type SMPEvent int

SMPEvent define the events used to indicate status of SMP to the UI

const (
	// SMPEventError means abort the current auth and update the auth progress dialog with progress_percent. This event is only sent when we receive a message for another message state than we are in
	SMPEventError SMPEvent = iota
	// SMPEventAbort means update the auth progress dialog with progress_percent
	SMPEventAbort
	// SMPEventCheated means abort the current auth and update the auth progress dialog with progress_percent
	SMPEventCheated
	// SMPEventAskForAnswer means ask the user to answer the secret question
	SMPEventAskForAnswer
	// SMPEventAskForSecret means prompt the user to enter a shared secret
	SMPEventAskForSecret
	// SMPEventInProgress means update the auth progress dialog with progress_percent
	SMPEventInProgress
	// SMPEventSuccess means update the auth progress dialog with progress_percent
	SMPEventSuccess
	// SMPEventFailure means update the auth progress dialog with progress_percent
	SMPEventFailure
)

func (SMPEvent) String

func (s SMPEvent) String() string

type SMPEventHandler

type SMPEventHandler interface {
	// HandleSMPEvent should update the authentication UI with respect to SMP events
	HandleSMPEvent(event SMPEvent, progressPercent int, question string)
}

SMPEventHandler handles SMPEvents

func CombineSMPEventHandlers

func CombineSMPEventHandlers(handlers ...SMPEventHandler) SMPEventHandler

CombineSMPEventHandlers creates a SMPEventHandler that will call all handlers given to this function. It ignores nil entries.

type SecurityEvent

type SecurityEvent int

SecurityEvent define the events used to indicate changes in security status. In comparison with libotr, this library does not take trust levels into concern for security events

const (
	// GoneInsecure is signalled when we have gone from a secure state to an insecure state
	GoneInsecure SecurityEvent = iota
	// GoneSecure is signalled when we have gone from an insecure state to a secure state
	GoneSecure
	// StillSecure is signalled when we have refreshed the security state but is still in a secure state
	StillSecure
)

func (SecurityEvent) String

func (s SecurityEvent) String() string

String returns the string representation of the SecurityEvent

type SecurityEventHandler

type SecurityEventHandler interface {
	// HandleSecurityEvent is called when a change in security status happens
	HandleSecurityEvent(event SecurityEvent)
}

SecurityEventHandler is an interface for events that are related to changes of security status

func CombineSecurityEventHandlers

func CombineSecurityEventHandlers(handlers ...SecurityEventHandler) SecurityEventHandler

CombineSecurityEventHandlers creates a SecurityEventHandler that will call all handlers given to this function. It ignores nil entries.

type ValidMessage

type ValidMessage []byte

ValidMessage is a message that has gone through fragmentation and is valid to send through the IM client Some encodedMessage instances are validMessage instances, but this depends on the fragmentation size

Directories

Path Synopsis