channels

package
v4.7.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 26, 2024 License: BSD-2-Clause, BSD-2-Clause Imports: 50 Imported by: 3

README

Channels provide a channels implementation on top of broadcast which is capable of handing the user facing features of channels, including replies, reactions, and eventually admin commands.

on sending, data propagates as follows:

Send function (Example: SendMessage) - > SendGeneric ->
Broadcast.BroadcastWithAssembler -> cmix.SendWithAssembler

on receiving messages propagate as follows:

cmix message pickup (by service)- > broadcast.Processor ->
userListener ->  events.triggerEvent ->
messageTypeHandler (example: Text) ->
eventModel (example: ReceiveMessage)

on sendingAdmin, data propagates as follows:

Send function - > SendAdminGeneric ->
Broadcast.BroadcastAsymmetricWithAssembler -> cmix.SendWithAssembler

on receiving admin messages propagate as follows:

cmix message pickup (by service)- > broadcast.Processor -> adminListener ->
events.triggerAdminEvent -> messageTypeHandler (example: Text) ->
eventModel (example: ReceiveMessage)

Documentation

Overview

Package channels provides a channels implementation on top of broadcast which is capable of handing the user facing features of channels, including replies, reactions, and eventually admin commands.

Index

Constants

View Source
const (

	// SendMessageTag is the base tag used when generating a debug tag for
	// sending a message.
	SendMessageTag = "ChMessage"

	// SendReplyTag is the base tag used when generating a debug tag for
	// sending a reply.
	SendReplyTag = "ChReply"

	// SendReactionTag is the base tag used when generating a debug tag for
	// sending a reaction.
	SendReactionTag = "ChReaction"

	// SendSilentTag is the base tag used when generating a debug tag for
	// sending a silent message.
	SendSilentTag = "ChSilent"

	// SendInviteTag is the base tag used when generating a debug tag for
	// sending an invitation.
	SendInviteTag = "ChInvite"

	// SendDeleteTag is the base tag used when generating a debug tag for a
	// delete message.
	SendDeleteTag = "ChDelete"

	// SendPinnedTag is the base tag used when generating a debug tag for a
	// pinned message.
	SendPinnedTag = "ChPinned"

	// SendMuteTag is the base tag used when generating a debug tag for a mute
	// message.
	SendMuteTag = "ChMute"

	// SendAdminReplayTag is the base tag used when generating a debug tag for
	// an admin replay message.
	SendAdminReplayTag = "ChAdminReplay"
)
View Source
const AdminUsername = "Admin"

AdminUsername defines the displayed username of admin messages, which are unique users for every channel defined by the channel's private key.

View Source
const (

	// MessageLife is how long a message is available from the network before it
	// expires from the network and is irretrievable from the gateways.
	MessageLife = 500 * time.Hour
)

Variables

View Source
var (
	// ChannelAlreadyExistsErr is returned when attempting to join a channel
	// that the user is already in.
	ChannelAlreadyExistsErr = errors.New(
		"the channel cannot be added because it already exists")

	// ChannelDoesNotExistsErr is returned when a channel does not exist.
	ChannelDoesNotExistsErr = errors.New("the channel cannot be found")

	// MessageTooLongErr is returned when attempting to send a message that is
	// too large.
	MessageTooLongErr = errors.New("the passed message is too long")

	// WrongPrivateKeyErr is returned when the private key does not match the
	// channel's public key.
	WrongPrivateKeyErr = errors.New(
		"the passed private key does not match the channel")

	// WrongPasswordErr is returned when the encrypted packet could not be
	// decrypted using the supplied password.
	WrongPasswordErr = errors.New(
		"incorrect password")

	// MessageTypeAlreadyRegistered is returned if a handler has already been
	// registered with the supplied message type. Only one handler can be
	// registered per type.
	MessageTypeAlreadyRegistered = errors.New(
		"the given message type has already been registered")
)
View Source
var AdminFakePubKey = ed25519.PublicKey{}

AdminFakePubKey is the placeholder for the Ed25519 public key used when the admin trigger calls a message handler.

View Source
var File_channelMessages_proto protoreflect.FileDescriptor
View Source
var NoMessageErr = errors.New("message does not exist [EV]")

NoMessageErr must be returned by EventModel methods (such as EventModel.UpdateFromUUID, EventModel.UpdateFromMessageID, and EventModel.GetMessage) when the message cannot be found.

View Source
var NotAnAdminErr = errors.New("user not a member of the channel")

NotAnAdminErr is returned if the user is attempting to do an admin command while not being an admin.

View Source
var ValidForever = time.Duration(math.MaxInt64)

ValidForever is used as a validUntil lease when sending to denote the message or operation never expires.

Note: A message relay must be present to enforce this otherwise things expire after 3 weeks due to network retention.

Functions

func CheckNoMessageErr added in v4.6.3

func CheckNoMessageErr(err error) bool

CheckNoMessageErr determines if the error returned by an EventModel function indicates that the message or item does not exist. It returns true if the error contains NoMessageErr.

Types

type ActionLeaseList added in v4.4.4

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

ActionLeaseList keeps a list of messages and actions and undoes each action when its lease is up.

func NewActionLeaseList added in v4.4.4

func NewActionLeaseList(triggerFn triggerActionEventFunc, store *CommandStore,
	kv versioned.KV, rng *fastRNG.StreamGenerator) *ActionLeaseList

NewActionLeaseList initialises a new empty ActionLeaseList.

func NewOrLoadActionLeaseList added in v4.4.4

func NewOrLoadActionLeaseList(triggerFn triggerActionEventFunc,
	store *CommandStore, kv versioned.KV, rng *fastRNG.StreamGenerator) (
	*ActionLeaseList, error)

NewOrLoadActionLeaseList loads an existing ActionLeaseList from storage, if it exists. Otherwise, it initialises a new empty ActionLeaseList.

func (*ActionLeaseList) AddMessage added in v4.4.4

func (all *ActionLeaseList) AddMessage(channelID *id.ID, messageID message.ID,
	action MessageType, unsanitizedPayload, sanitizedPayload,
	encryptedPayload []byte, timestamp, originatingTimestamp time.Time,
	lease time.Duration, originatingRound id.Round, round rounds.Round,
	fromAdmin bool) error

AddMessage triggers the lease message for insertion. An error is returned if the message should be dropped. A message is dropped if its lease has expired already or if it is older than an already stored replay for the command.

func (*ActionLeaseList) AddOrOverwrite added in v4.4.4

func (all *ActionLeaseList) AddOrOverwrite(channelID *id.ID, action MessageType,
	payload []byte) error

AddOrOverwrite adds a new lease or overwrites an existing lease to trigger a replay soon (between 3 and 10 minutes).

func (*ActionLeaseList) RegisterReplayFn added in v4.4.4

func (all *ActionLeaseList) RegisterReplayFn(replayFn ReplayActionFunc)

RegisterReplayFn registers the function that is called to replay an action.

func (*ActionLeaseList) RemoveChannel added in v4.4.4

func (all *ActionLeaseList) RemoveChannel(channelID *id.ID)

RemoveChannel triggers all leases for the channel for removal.

func (*ActionLeaseList) RemoveMessage added in v4.4.4

func (all *ActionLeaseList) RemoveMessage(channelID *id.ID,
	messageID message.ID, action MessageType, unsanitizedPayload,
	sanitizedPayload, encryptedPayload []byte, timestamp,
	originatingTimestamp time.Time, lease time.Duration,
	originatingRound id.Round, round rounds.Round, fromAdmin bool) error

RemoveMessage triggers the lease message for removal. An error is returned if the message should be dropped. A message is dropped if its lease has expired already or if it is older than an already stored replay for the command.

func (*ActionLeaseList) StartProcesses added in v4.4.4

func (all *ActionLeaseList) StartProcesses() (stoppable.Stoppable, error)

StartProcesses starts the thread that checks for expired action leases and undoes the action. This function adheres to the xxdk.Service type.

This function always returns a nil error.

type ActionSaver added in v4.6.3

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

ActionSaver saves actions that are received that do not apply to any message in storage. The actions are saved and checked against each new message to see if they apply.

func NewActionSaver added in v4.6.3

func NewActionSaver(
	triggerFn triggerActionEventFunc, kv versioned.KV) *ActionSaver

NewActionSaver initialises a new empty ActionSaver.

func (*ActionSaver) AddAction added in v4.6.3

func (as *ActionSaver) AddAction(channelID *id.ID, messageID,
	targetMessage message.ID, action MessageType, content,
	encryptedPayload []byte, timestamp, originatingTimestamp, received time.Time,
	lease time.Duration, originatingRound id.Round, round rounds.Round,
	fromAdmin bool) error

AddAction inserts the saved action into the ordered list and map keyed on the target message.

func (*ActionSaver) CheckSavedActions added in v4.6.3

func (as *ActionSaver) CheckSavedActions(
	channelID *id.ID, targetMessage message.ID) (UpdateActionFn, bool)

CheckSavedActions checks if there is a saved action for the message and channel ID. If there are no saved actions for the message, then this function returns nil and false. If there is a saved delete action, then CheckSavedActions returns true and the message should be dropped and not be passed to the event model. If there is a non-delete action, then an UpdateActionFn is returned that must be called after the message is passed to the event model.

func (*ActionSaver) RemoveChannel added in v4.6.3

func (as *ActionSaver) RemoveChannel(channelID *id.ID) error

RemoveChannel removes each saved action for the channel from the ordered list and removes the channel from the map. Also deletes from storage.

RemoveChannel should be called when leaving a channel.

func (*ActionSaver) StartProcesses added in v4.6.3

func (as *ActionSaver) StartProcesses() (stoppable.Stoppable, error)

StartProcesses starts the thread that checks for expired action leases and undoes the action. This function adheres to the xxdk.Service type.

This function always returns a nil error.

type AddServiceFn added in v4.4.4

type AddServiceFn func(sp xxdk.Service) error

AddServiceFn adds a service to be controlled by the client thread control. These will be started and stopped with the network follower.

This type must match [Client.AddService].

type AllowLists added in v4.7.1

type AllowLists struct {
	// AllowWithTags is a list of message types that are not filtered when
	// there are Tags.
	AllowWithTags map[MessageType]struct{} `json:"allowWithTags"`

	// AllowWithoutTags is a list of message types that are not filtered when
	// there are no Tags.
	AllowWithoutTags map[MessageType]struct{} `json:"allowWithoutTags"`
}

AllowLists contains the list of messages types allowed with or without tags.

type CMIXChannelDelete added in v4.4.4

type CMIXChannelDelete struct {
	Version   uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	MessageID []byte `protobuf:"bytes,2,opt,name=messageID,proto3" json:"messageID,omitempty"` // The [channel.MessageID] of the message to delete
	// contains filtered or unexported fields
}

CMIXChannelDelete is the payload for a Delete MessageType. It deletes the message with the messageID from storage.

func (*CMIXChannelDelete) Descriptor deprecated added in v4.4.4

func (*CMIXChannelDelete) Descriptor() ([]byte, []int)

Deprecated: Use CMIXChannelDelete.ProtoReflect.Descriptor instead.

func (*CMIXChannelDelete) GetMessageID added in v4.4.4

func (x *CMIXChannelDelete) GetMessageID() []byte

func (*CMIXChannelDelete) GetVersion added in v4.4.4

func (x *CMIXChannelDelete) GetVersion() uint32

func (*CMIXChannelDelete) ProtoMessage added in v4.4.4

func (*CMIXChannelDelete) ProtoMessage()

func (*CMIXChannelDelete) ProtoReflect added in v4.4.4

func (x *CMIXChannelDelete) ProtoReflect() protoreflect.Message

func (*CMIXChannelDelete) Reset added in v4.4.4

func (x *CMIXChannelDelete) Reset()

func (*CMIXChannelDelete) String added in v4.4.4

func (x *CMIXChannelDelete) String() string

type CMIXChannelInvitation added in v4.7.1

type CMIXChannelInvitation struct {
	Version    uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	Text       string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
	InviteLink string `protobuf:"bytes,3,opt,name=inviteLink,proto3" json:"inviteLink,omitempty"`
	Password   string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"`
	// contains filtered or unexported fields
}

CMIXChannelInvitation is the payload for a Invitation MessageType. It invites members of a channel to a separate channel.

func (*CMIXChannelInvitation) Descriptor deprecated added in v4.7.1

func (*CMIXChannelInvitation) Descriptor() ([]byte, []int)

Deprecated: Use CMIXChannelInvitation.ProtoReflect.Descriptor instead.

func (x *CMIXChannelInvitation) GetInviteLink() string

func (*CMIXChannelInvitation) GetPassword added in v4.7.1

func (x *CMIXChannelInvitation) GetPassword() string

func (*CMIXChannelInvitation) GetText added in v4.7.1

func (x *CMIXChannelInvitation) GetText() string

func (*CMIXChannelInvitation) GetVersion added in v4.7.1

func (x *CMIXChannelInvitation) GetVersion() uint32

func (*CMIXChannelInvitation) ProtoMessage added in v4.7.1

func (*CMIXChannelInvitation) ProtoMessage()

func (*CMIXChannelInvitation) ProtoReflect added in v4.7.1

func (x *CMIXChannelInvitation) ProtoReflect() protoreflect.Message

func (*CMIXChannelInvitation) Reset added in v4.7.1

func (x *CMIXChannelInvitation) Reset()

func (*CMIXChannelInvitation) String added in v4.7.1

func (x *CMIXChannelInvitation) String() string

type CMIXChannelMute added in v4.4.4

type CMIXChannelMute struct {
	Version    uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	PubKey     []byte `protobuf:"bytes,2,opt,name=pubKey,proto3" json:"pubKey,omitempty"`          // The [ed25519.PublicKey] of the user to mute
	UndoAction bool   `protobuf:"varint,3,opt,name=undoAction,proto3" json:"undoAction,omitempty"` // If true, the user is un-muted
	// contains filtered or unexported fields
}

CMIXChannelMute is the payload for a Mute MessageType. It mutes a specific user so all future messages from them will be dropped when received. It also prevents the user from sending messages.

func (*CMIXChannelMute) Descriptor deprecated added in v4.4.4

func (*CMIXChannelMute) Descriptor() ([]byte, []int)

Deprecated: Use CMIXChannelMute.ProtoReflect.Descriptor instead.

func (*CMIXChannelMute) GetPubKey added in v4.4.4

func (x *CMIXChannelMute) GetPubKey() []byte

func (*CMIXChannelMute) GetUndoAction added in v4.4.4

func (x *CMIXChannelMute) GetUndoAction() bool

func (*CMIXChannelMute) GetVersion added in v4.4.4

func (x *CMIXChannelMute) GetVersion() uint32

func (*CMIXChannelMute) ProtoMessage added in v4.4.4

func (*CMIXChannelMute) ProtoMessage()

func (*CMIXChannelMute) ProtoReflect added in v4.4.4

func (x *CMIXChannelMute) ProtoReflect() protoreflect.Message

func (*CMIXChannelMute) Reset added in v4.4.4

func (x *CMIXChannelMute) Reset()

func (*CMIXChannelMute) String added in v4.4.4

func (x *CMIXChannelMute) String() string

type CMIXChannelPinned added in v4.4.4

type CMIXChannelPinned struct {
	Version    uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	MessageID  []byte `protobuf:"bytes,2,opt,name=messageID,proto3" json:"messageID,omitempty"`    // The [channel.MessageID] of the message to pin
	UndoAction bool   `protobuf:"varint,3,opt,name=undoAction,proto3" json:"undoAction,omitempty"` // If true, the message is unpinned
	// contains filtered or unexported fields
}

CMIXChannelPinned is the payload for a Pinned MessageType. It pins a specific message to a channel.

func (*CMIXChannelPinned) Descriptor deprecated added in v4.4.4

func (*CMIXChannelPinned) Descriptor() ([]byte, []int)

Deprecated: Use CMIXChannelPinned.ProtoReflect.Descriptor instead.

func (*CMIXChannelPinned) GetMessageID added in v4.4.4

func (x *CMIXChannelPinned) GetMessageID() []byte

func (*CMIXChannelPinned) GetUndoAction added in v4.4.4

func (x *CMIXChannelPinned) GetUndoAction() bool

func (*CMIXChannelPinned) GetVersion added in v4.4.4

func (x *CMIXChannelPinned) GetVersion() uint32

func (*CMIXChannelPinned) ProtoMessage added in v4.4.4

func (*CMIXChannelPinned) ProtoMessage()

func (*CMIXChannelPinned) ProtoReflect added in v4.4.4

func (x *CMIXChannelPinned) ProtoReflect() protoreflect.Message

func (*CMIXChannelPinned) Reset added in v4.4.4

func (x *CMIXChannelPinned) Reset()

func (*CMIXChannelPinned) String added in v4.4.4

func (x *CMIXChannelPinned) String() string

type CMIXChannelReaction

type CMIXChannelReaction struct {
	Version           uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,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"`
	// contains filtered or unexported fields
}

CMIXChannelReaction is the payload for reactions. The reaction must be a single emoji and the reactionMessageID must be non nil and a real message in the channel.

func (*CMIXChannelReaction) Descriptor deprecated

func (*CMIXChannelReaction) Descriptor() ([]byte, []int)

Deprecated: Use CMIXChannelReaction.ProtoReflect.Descriptor instead.

func (*CMIXChannelReaction) GetReaction

func (x *CMIXChannelReaction) GetReaction() string

func (*CMIXChannelReaction) GetReactionMessageID

func (x *CMIXChannelReaction) GetReactionMessageID() []byte

func (*CMIXChannelReaction) GetVersion

func (x *CMIXChannelReaction) GetVersion() uint32

func (*CMIXChannelReaction) ProtoMessage

func (*CMIXChannelReaction) ProtoMessage()

func (*CMIXChannelReaction) ProtoReflect

func (x *CMIXChannelReaction) ProtoReflect() protoreflect.Message

func (*CMIXChannelReaction) Reset

func (x *CMIXChannelReaction) Reset()

func (*CMIXChannelReaction) String

func (x *CMIXChannelReaction) String() string

type CMIXChannelSilentMessage added in v4.7.1

type CMIXChannelSilentMessage struct {
	Version uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	// contains filtered or unexported fields
}

CMIXSilentMessage is the payload for a Silent MessageType. Its primary purpose is to communicate new nicknames without sending a CMIXChannelText.

func (*CMIXChannelSilentMessage) Descriptor deprecated added in v4.7.1

func (*CMIXChannelSilentMessage) Descriptor() ([]byte, []int)

Deprecated: Use CMIXChannelSilentMessage.ProtoReflect.Descriptor instead.

func (*CMIXChannelSilentMessage) GetVersion added in v4.7.1

func (x *CMIXChannelSilentMessage) GetVersion() uint32

func (*CMIXChannelSilentMessage) ProtoMessage added in v4.7.1

func (*CMIXChannelSilentMessage) ProtoMessage()

func (*CMIXChannelSilentMessage) ProtoReflect added in v4.7.1

func (x *CMIXChannelSilentMessage) ProtoReflect() protoreflect.Message

func (*CMIXChannelSilentMessage) Reset added in v4.7.1

func (x *CMIXChannelSilentMessage) Reset()

func (*CMIXChannelSilentMessage) String added in v4.7.1

func (x *CMIXChannelSilentMessage) String() string

type CMIXChannelText

type CMIXChannelText struct {
	Version        uint32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
	Text           string `protobuf:"bytes,2,opt,name=text,proto3" json:"text,omitempty"`
	ReplyMessageID []byte `protobuf:"bytes,3,opt,name=replyMessageID,proto3" json:"replyMessageID,omitempty"`
	// contains filtered or unexported fields
}

CMIXChannelText is the payload for sending normal text messages to channels the replyMessageID is nil when it is not a reply.

func (*CMIXChannelText) Descriptor deprecated

func (*CMIXChannelText) Descriptor() ([]byte, []int)

Deprecated: Use CMIXChannelText.ProtoReflect.Descriptor instead.

func (*CMIXChannelText) GetReplyMessageID

func (x *CMIXChannelText) GetReplyMessageID() []byte

func (*CMIXChannelText) GetText

func (x *CMIXChannelText) GetText() string

func (*CMIXChannelText) GetVersion

func (x *CMIXChannelText) GetVersion() uint32

func (*CMIXChannelText) ProtoMessage

func (*CMIXChannelText) ProtoMessage()

func (*CMIXChannelText) ProtoReflect

func (x *CMIXChannelText) ProtoReflect() protoreflect.Message

func (*CMIXChannelText) Reset

func (x *CMIXChannelText) Reset()

func (*CMIXChannelText) String

func (x *CMIXChannelText) String() string

type ChannelMessage

type ChannelMessage struct {

	// Lease is the length that this channel message will take effect.
	Lease int64 `protobuf:"varint,1,opt,name=Lease,proto3" json:"Lease,omitempty"`
	// The round this message was sent on.
	RoundID uint64 `protobuf:"varint,2,opt,name=RoundID,proto3" json:"RoundID,omitempty"`
	// Payload is the actual message payload. It will be processed differently
	// based on the PayloadType.
	Payload []byte `protobuf:"bytes,4,opt,name=Payload,proto3" json:"Payload,omitempty"`
	// nickname is the name which the user is using for this message it will not
	// be longer than 24 characters.
	Nickname string `protobuf:"bytes,5,opt,name=Nickname,proto3" json:"Nickname,omitempty"`
	// Nonce is 32 bits of randomness to ensure that two messages in the same
	// round with that have the same nickname, payload, and lease will not have
	// the same message ID.
	Nonce []byte `protobuf:"bytes,6,opt,name=Nonce,proto3" json:"Nonce,omitempty"`
	// LocalTimestamp is the timestamp (unix nanoseconds) when the "send call"
	// is made based upon the local clock. If this differs by more than 5
	// seconds +/- from when the round it sent on is queued, then a random
	// mutation on the queued time (+/- 200ms) will be used by local clients
	// instead.
	LocalTimestamp int64  `protobuf:"varint,7,opt,name=LocalTimestamp,proto3" json:"LocalTimestamp,omitempty"`
	DMToken        uint32 `protobuf:"varint,8,opt,name=DMToken,proto3" json:"DMToken,omitempty"` // hash of private key
	// contains filtered or unexported fields
}

ChannelMessage is transmitted by the channel. Effectively it is a command for the channel sent by a user with admin access of the channel.

func (*ChannelMessage) Descriptor deprecated

func (*ChannelMessage) Descriptor() ([]byte, []int)

Deprecated: Use ChannelMessage.ProtoReflect.Descriptor instead.

func (*ChannelMessage) GetDMToken added in v4.4.4

func (x *ChannelMessage) GetDMToken() uint32

func (*ChannelMessage) GetLease

func (x *ChannelMessage) GetLease() int64

func (*ChannelMessage) GetLocalTimestamp

func (x *ChannelMessage) GetLocalTimestamp() int64

func (*ChannelMessage) GetNickname

func (x *ChannelMessage) GetNickname() string

func (*ChannelMessage) GetNonce

func (x *ChannelMessage) GetNonce() []byte

func (*ChannelMessage) GetPayload

func (x *ChannelMessage) GetPayload() []byte

func (*ChannelMessage) GetRoundID

func (x *ChannelMessage) GetRoundID() uint64

func (*ChannelMessage) ProtoMessage

func (*ChannelMessage) ProtoMessage()

func (*ChannelMessage) ProtoReflect

func (x *ChannelMessage) ProtoReflect() protoreflect.Message

func (*ChannelMessage) Reset

func (x *ChannelMessage) Reset()

func (*ChannelMessage) String

func (x *ChannelMessage) String() string

type Client

type Client interface {
	GetMaxMessageLength() int
	SendWithAssembler(recipient *id.ID, assembler cmix.MessageAssembler,
		cmixParams cmix.CMIXParams) (rounds.Round, ephemeral.Id, error)
	AddIdentity(id *id.ID, validUntil time.Time, persistent bool,
		fallthroughProcessor message.Processor)
	AddIdentityWithHistory(
		id *id.ID, validUntil, beginning time.Time,
		persistent bool, fallthroughProcessor message.Processor)
	RemoveIdentity(id *id.ID)
	AddService(clientID *id.ID, newService message.Service,
		response message.Processor)
	UpsertCompressedService(clientID *id.ID, newService message.CompressedService,
		response message.Processor)
	DeleteClientService(clientID *id.ID)
	IsHealthy() bool
	AddHealthCallback(f func(bool)) uint64
	RemoveHealthCallback(uint64)
	GetRoundResults(timeout time.Duration, roundCallback cmix.RoundEventCallback,
		roundList ...id.Round)
}

Client contains the methods from cmix.Client that are required by the Manager.

type CommandMessage added in v4.4.4

type CommandMessage struct {
	// ChannelID is the ID of the channel.
	ChannelID *id.ID `json:"channelID,omitempty"`

	// MessageID is the ID of the message.
	MessageID message.ID `json:"messageID,omitempty"`

	// MessageType is the Type of channel message.
	MessageType MessageType `json:"messageType,omitempty"`

	// Nickname is the nickname of the sender.
	Nickname string `json:"nickname,omitempty"`

	// Content is the message contents. In most cases, this is the various
	// marshalled proto messages (e.g., channels.CMIXChannelText and
	// channels.CMIXChannelDelete).
	Content []byte `json:"content,omitempty"`

	// EncryptedPayload is the encrypted contents of the received format.Message
	// (with its outer layer of encryption removed). This is the encrypted
	// channels.ChannelMessage.
	EncryptedPayload []byte `json:"encryptedPayload,omitempty"`

	// PubKey is the Ed25519 public key of the sender.
	PubKey ed25519.PublicKey `json:"pubKey,omitempty"`

	// Codeset is the codeset version.
	Codeset uint8 `json:"codeset,omitempty"`

	// Timestamp is the time that the round was queued. It is set by the
	// listener to be either ChannelMessage.LocalTimestamp or the timestamp for
	// states.QUEUED of the round it was sent on, if that is significantly later
	// than OriginatingTimestamp. If the message is a replay, then Timestamp
	// will
	// always be the queued time of the round.
	Timestamp time.Time `json:"timestamp,omitempty"`

	// OriginatingTimestamp is the time the sender queued the message for
	// sending on their client.
	OriginatingTimestamp time.Time `json:"originatingTimestamp,omitempty"`

	// Lease is how long the message should persist.
	Lease time.Duration `json:"lease,omitempty"`

	// OriginatingRound is the ID of the round the message was originally sent
	// on.
	OriginatingRound id.Round `json:"originatingRound,omitempty"`

	// Round is the information about the round the message was sent on. For
	// replay messages, this is the round of the most recent replay, not the
	// round of the original message.
	Round rounds.Round `json:"round,omitempty"`

	// Status is the current status of the message. It is set to Delivered by
	// the listener.
	Status SentStatus `json:"status,omitempty"`

	// FromAdmin indicates if the message came from the channel admin.
	FromAdmin bool `json:"fromAdmin,omitempty"`

	// UserMuted indicates if the sender of the message is muted.
	UserMuted bool `json:"userMuted,omitempty"`
}

CommandMessage contains all the information about a command channel message that will be saved to storage

type CommandStore added in v4.4.4

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

CommandStore stores message information about channel commands in storage. Each message

func NewCommandStore added in v4.4.4

func NewCommandStore(kv versioned.KV) *CommandStore

NewCommandStore initialises a new message CommandStore object with a prefixed KV.

func (*CommandStore) DeleteCommand added in v4.4.4

func (cs *CommandStore) DeleteCommand(
	channelID *id.ID, messageType MessageType, content []byte) error

DeleteCommand deletes the command message from storage.

func (*CommandStore) LoadCommand added in v4.4.4

func (cs *CommandStore) LoadCommand(channelID *id.ID,
	messageType MessageType, content []byte) (*CommandMessage, error)

LoadCommand loads the command message from storage.

func (*CommandStore) SaveCommand added in v4.4.4

func (cs *CommandStore) SaveCommand(channelID *id.ID, messageID message.ID,
	messageType MessageType, nickname string, content, encryptedPayload []byte,
	pubKey ed25519.PublicKey, codeset uint8, timestamp,
	originatingTimestamp time.Time, lease time.Duration,
	originatingRound id.Round, round rounds.Round, status SentStatus, fromAdmin,
	userMuted bool) error

SaveCommand stores the command message and its data to storage.

type EventModel

type EventModel interface {
	// JoinChannel is called whenever a channel is joined locally.
	JoinChannel(channel *cryptoBroadcast.Channel)

	// LeaveChannel is called whenever a channel is left locally.
	LeaveChannel(channelID *id.ID)

	// ReceiveMessage is called whenever a message is received on a given
	// channel. It may be called multiple times on the same message. It is
	// incumbent on the user of the API to filter such called by message ID.
	//
	// The API needs to return a UUID of the message that can be referenced at a
	// later time.
	//
	// messageID, timestamp, and round are all nillable and may be updated based
	// upon the UUID at a later date. A time of time.Time{} will be passed for a
	// nilled timestamp.
	//
	// nickname may be empty, in which case the UI is expected to display the
	// codename.
	//
	// messageType type is included in the call; it will always be Text (1) for
	// this call, but it may be required in downstream databases.
	ReceiveMessage(channelID *id.ID, messageID message.ID, nickname,
		text string, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8,
		timestamp time.Time, lease time.Duration, round rounds.Round,
		messageType MessageType, status SentStatus, hidden bool) uint64

	// ReceiveReply is called whenever a message is received that is a reply on
	// a given channel. It may be called multiple times on the same message. It
	// is incumbent on the user of the API to filter such called by message ID.
	//
	// Messages may arrive our of order, so a reply, in theory, can arrive
	// before the initial message. As a result, it may be important to buffer
	// replies.
	//
	// The API needs to return a UUID of the message that can be referenced at a
	// later time.
	//
	// messageID, timestamp, and round are all nillable and may be updated based
	// upon the UUID at a later date. A time of time.Time{} will be passed for a
	// nilled timestamp.
	//
	// nickname may be empty, in which case the UI is expected to display the
	// codename.
	//
	// messageType type is included in the call; it will always be Text (1) for
	// this call, but it may be required in downstream databases.
	ReceiveReply(channelID *id.ID, messageID, reactionTo message.ID, nickname,
		text string, pubKey ed25519.PublicKey, dmToken uint32, codeset uint8,
		timestamp time.Time, lease time.Duration, round rounds.Round,
		messageType MessageType, status SentStatus, hidden bool) uint64

	// ReceiveReaction is called whenever a reaction to a message is received on
	// a given channel. It may be called multiple times on the same reaction. It
	// is incumbent on the user of the API to filter such called by message ID.
	//
	// Messages may arrive our of order, so a reply, in theory, can arrive
	// before the initial message. As a result, it may be important to buffer
	// replies.
	//
	// The API needs to return a UUID of the message that can be referenced at a
	// later time.
	//
	// messageID, timestamp, and round are all nillable and may be updated based
	// upon the UUID at a later date. A time of time.Time{} will be passed for a
	// nilled timestamp.
	//
	// nickname may be empty, in which case the UI is expected to display the
	// codename.
	//
	// messageType type is included in the call; it will always be Text (1) for
	// this call, but it may be required in downstream databases.
	ReceiveReaction(channelID *id.ID, messageID, reactionTo message.ID,
		nickname, reaction string, pubKey ed25519.PublicKey, dmToken uint32,
		codeset uint8, timestamp time.Time, lease time.Duration,
		round rounds.Round, messageType MessageType, status SentStatus,
		hidden bool) uint64

	// UpdateFromUUID is called whenever a message at the UUID is modified.
	//
	// messageID, timestamp, round, pinned, hidden, and status are all nillable
	// and may be updated based upon the UUID at a later date. If a nil value is
	// passed, then make no update.
	//
	// Returns an error if the message cannot be updated. It must return
	// NoMessageErr if the message does not exist.
	UpdateFromUUID(uuid uint64, messageID *message.ID, timestamp *time.Time,
		round *rounds.Round, pinned, hidden *bool, status *SentStatus) error

	// UpdateFromMessageID is called whenever a message with the message ID is
	// modified.
	//
	// The API needs to return the UUID of the modified message that can be
	// referenced at a later time.
	//
	// timestamp, round, pinned, hidden, and status are all nillable and may be
	// updated based upon the UUID at a later date. If a nil value is passed,
	// then make no update.
	//
	// Returns an error if the message cannot be updated. It must return
	// NoMessageErr if the message does not exist.
	UpdateFromMessageID(messageID message.ID, timestamp *time.Time,
		round *rounds.Round, pinned, hidden *bool, status *SentStatus) (
		uint64, error)

	// GetMessage returns the message with the given channel.MessageID.
	//
	// Returns an error if the message cannot be gotten. It must return
	// NoMessageErr if the message does not exist.
	GetMessage(messageID message.ID) (ModelMessage, error)

	// DeleteMessage deletes the message with the given [channel.MessageID] from
	// the database.
	//
	// Returns an error if the message cannot be deleted. It must return
	// NoMessageErr if the message does not exist.
	DeleteMessage(messageID message.ID) error

	// MuteUser is called whenever a user is muted or unmuted.
	MuteUser(channelID *id.ID, pubKey ed25519.PublicKey, unmute bool)
}

EventModel is an interface which an external party which uses the channels system passed an object which adheres to in order to get events on the channel.

type EventModelBuilder

type EventModelBuilder func(path string) (EventModel, error)

EventModelBuilder initialises the event model using the given path.

type ExtensionBuilder added in v4.6.3

type ExtensionBuilder func(e EventModel, m Manager,
	me cryptoChannel.PrivateIdentity) ([]ExtensionMessageHandler, error)

ExtensionBuilder builds an extension off of an event model. It must cast the event model to its event model type and return an error if the cast fails. It returns a slice of ExtensionMessageHandler that contains the handlers for every custom message type that the extension will handle.

Note: The first thing the function should do is extract the extension's event model using the call:

eventModel, success := e.(ExtensionEventModel)

It should return an error if the casting is a failure.

type ExtensionMessageHandler added in v4.6.3

type ExtensionMessageHandler interface {
	// GetType registers the message type that this handler is for. All messages
	// of this type will be passed through this handler.
	GetType() MessageType

	// GetProperties returns debugging and pre-filtering information.
	//
	// Parameters:
	//   - name - A name that is included in log messages for debugging.
	//   - userSpace - If true, then normal user messages will be passed to the
	//     handler, otherwise it is dropped.
	//   - adminSpace - If true, then admin messages will be passed to the
	//     handler, otherwise it is dropped.
	//   - mutedSpace - If true, then muted user messages will be passed to the
	//     handler, otherwise it is dropped.
	//
	// userSpace or adminSpace must be true or all messages will be ignored
	GetProperties() (name string, userSpace, adminSpace, mutedSpace bool)

	// Handle is called when the message is actually received.
	//
	// Parameters:
	//	 - channelID - ID of the channel that the message belongs to.
	//	 - messageID - Unique ID of the message. May not be present if this
	//	   user is the sender.
	//   - messageType - The type of the message. It will always be the same as
	//     GetType.
	//   - nickname - Sender's chosen username. It will be "admin" if it is sent
	//     by a channel administrator.
	//	 - content - The decrypted contents of the payload. This is the actual
	//	   message contents sent from the sender.
	//   - encryptedPayload - Encrypted contents of the received format.Message,
	//     which is the encrypted channels.ChannelMessage. It is used for some
	//     specific admin interactions.
	//   - pubKey - The Ed25519 public key of the sender.
	//   - dmToken - An optional token that the sender may add to allow any
	//     recipient to message them directly.
	//   - codeset - Codename generation version.
	//   - timestamp - Time the message was sent according to the sender.
	//   - originatingTimestamp - The time the mix round the message was
	//     originally sent on started.
	//   - lease - How long the message should persist. The behavior of the
	//     lease is subject to what the extension author wants.
	//   - originatingRound - The ID of the round the message was originally
	//     sent on.
	//   - round - All known details of the round the message was sent on.
	//   - status - The current state of the message, if it is queued to send,
	//     has been sent, and if it has been delivered. Unless this client is
	//     the sender, it will always be Delivered.
	//   - fromAdmin - Indicates if the message came from the channel admin.
	//   - hidden - Designation that the message should not be shown.
	Handle(channelID *id.ID, messageID message.ID, messageType MessageType,
		nickname string, content, encryptedPayload []byte,
		pubKey ed25519.PublicKey, dmToken uint32, codeset uint8, timestamp,
		originatingTimestamp time.Time, lease time.Duration,
		originatingRound id.Round, round rounds.Round, status SentStatus,
		fromAdmin, hidden bool) uint64

	// GetNotificationTags is called to get the asymmetric and symmetric allow
	// lists for the given channel at the specified level that are appended to
	// the [NotificationFilter].
	GetNotificationTags(channelID *id.ID, level NotificationLevel) (
		asymmetric, symmetric AllowLists)
}

ExtensionMessageHandler is the mechanism by which extensions register their message handlers with the event model.

type Manager

type Manager interface {

	// GenerateChannel creates a new channel with the user as the admin and
	// returns the broadcast.Channel object. This function only create a channel
	// and does not join it.
	//
	// The private key is saved to storage and can be accessed with
	// ExportChannelAdminKey.
	//
	// Parameters:
	//   - name - The name of the new channel. The name must be between 3 and 24
	//     characters inclusive. It can only include upper and lowercase Unicode
	//     letters, digits 0 through 9, and underscores (_). It cannot be
	//     changed once a channel is created.
	//   - description - The description of a channel. The description is
	//     optional but cannot be longer than 144 characters and can include all
	//     Unicode characters. It cannot be changed once a channel is created.
	//   - privacyLevel - The broadcast.PrivacyLevel of the channel.
	GenerateChannel(
		name, description string, privacyLevel cryptoBroadcast.PrivacyLevel) (
		*cryptoBroadcast.Channel, error)

	// JoinChannel joins the given channel. It will return the error
	// ChannelAlreadyExistsErr if the channel has already been joined.
	JoinChannel(channel *cryptoBroadcast.Channel) error

	// LeaveChannel leaves the given channel. It will return the error
	// ChannelDoesNotExistsErr if the channel was not previously joined.
	LeaveChannel(channelID *id.ID) error

	// EnableDirectMessages enables the token for direct messaging for this
	// channel.
	EnableDirectMessages(chId *id.ID) error

	// DisableDirectMessages removes the token for direct messaging for a
	// given channel.
	DisableDirectMessages(chId *id.ID) error

	// AreDMsEnabled returns the status of DMs for a given channel;
	// returns true if DMs are enabled.
	AreDMsEnabled(chId *id.ID) bool

	// ReplayChannel replays all messages from the channel within the network's
	// memory (~3 weeks) over the event model. It does this by wiping the
	// underlying state tracking for message pickup for the channel, causing all
	// messages to be re-retrieved from the network.
	//
	// Returns the error ChannelDoesNotExistsErr if the channel was not
	// previously joined.
	ReplayChannel(channelID *id.ID) error

	// GetChannels returns the IDs of all channels that have been joined.
	GetChannels() []*id.ID

	// GetChannel returns the underlying cryptographic structure for a given
	// channel.
	//
	// Returns the error ChannelDoesNotExistsErr if the channel was not
	// previously joined.
	GetChannel(channelID *id.ID) (*cryptoBroadcast.Channel, error)

	// SendGeneric is used to send a raw message over a channel. In general, it
	// should be wrapped in a function that defines the wire protocol.
	//
	// If the final message, before being sent over the wire, is too long, this
	// will return an error. Due to the underlying encoding using compression,
	// it is not possible to define the largest payload that can be sent, but it
	// will always be possible to send a payload of 802 bytes at minimum.
	//
	// The meaning of validUntil depends on the use case.
	//
	// Set tracked to true if the message should be tracked in the sendTracker,
	// which allows messages to be shown locally before they are received on the
	// network. In general, all messages that will be displayed to the user
	// should be tracked while all actions should not be. More technically, any
	// messageType that corresponds to a handler that does not return a unique
	// ID (i.e., always returns 0) cannot be tracked, or it will cause errors.
	SendGeneric(channelID *id.ID, messageType MessageType, msg []byte,
		validUntil time.Duration, tracked bool, params cmix.CMIXParams,
		pingsMap map[PingType][]ed25519.PublicKey) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// SendMessage is used to send a formatted message over a channel.
	//
	// Due to the underlying encoding using compression, it is not possible to
	// define the largest payload that can be sent, but it will always be
	// possible to send a payload of 798 bytes at minimum.
	//
	// The message will auto delete validUntil after the round it is sent in,
	// lasting forever if ValidForever is used.
	SendMessage(channelID *id.ID, msg string, validUntil time.Duration,
		params cmix.CMIXParams, pings []ed25519.PublicKey) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// SendReply is used to send a formatted message over a channel.
	//
	// Due to the underlying encoding using compression, it is not possible to
	// define the largest payload that can be sent, but it will always be
	// possible to send a payload of 766 bytes at minimum.
	//
	// If the message ID that the reply is sent to does not exist, then the
	// other side will post the message as a normal message and not as a reply.
	//
	// The message will auto delete validUntil after the round it is sent in,
	// lasting forever if ValidForever is used.
	SendReply(channelID *id.ID, msg string, replyTo message.ID,
		validUntil time.Duration, params cmix.CMIXParams,
		pings []ed25519.PublicKey) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// SendReaction is used to send a reaction to a message over a channel. The
	// reaction must be a single emoji with no other characters, and will be
	// rejected otherwise.
	//
	// Clients will drop the reaction if they do not recognize the reactTo
	// message.
	//
	// The message will auto delete validUntil after the round it is sent in,
	// lasting forever if ValidForever is used.
	SendReaction(channelID *id.ID, reaction string, reactTo message.ID,
		validUntil time.Duration, params cmix.CMIXParams) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// SendSilent is used to send to a channel a message with no notifications.
	// Its primary purpose is to communicate new nicknames without calling
	// SendMessage.
	//
	// It takes no payload intentionally as the message should be very
	// lightweight.
	SendSilent(channelID *id.ID, validUntil time.Duration,
		params cmix.CMIXParams) (message.ID, rounds.Round, ephemeral.Id, error)

	// SendInvite is used to send to a channel (invited) an invitation to another
	// channel (invitee).
	//
	// If the channel ID for the invitee channel is not recognized by the Manager,
	// then an error will be returned.
	//
	// See [Manager.SendGeneric] for details on payload size limitations and
	// elaboration of pings.
	SendInvite(channelID *id.ID, msg string, inviteTo *cryptoBroadcast.Channel,
		host string,
		validUntil time.Duration, params cmix.CMIXParams,
		pings []ed25519.PublicKey) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// SendAdminGeneric is used to send a raw message over a channel encrypted
	// with admin keys, identifying it as sent by the admin. In general, it
	// should be wrapped in a function that defines the wire protocol.
	//
	// If the final message, before being sent over the wire, is too long, this
	// will return an error. The message must be at most 510 bytes long.
	//
	// If the user is not an admin of the channel (i.e. does not have a private
	// key for the channel saved to storage), then the error NotAnAdminErr is
	// returned.
	//
	// Set tracked to true if the message should be tracked in the sendTracker,
	// which allows messages to be shown locally before they are received on the
	// network. In general, all messages that will be displayed to the user
	// should be tracked while all actions should not be. More technically, any
	// messageType that corresponds to a handler that does not return a unique
	// ID (i.e., always returns 0) cannot be tracked, or it will cause errors.
	SendAdminGeneric(channelID *id.ID, messageType MessageType, msg []byte,
		validUntil time.Duration, tracked bool, params cmix.CMIXParams) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// DeleteMessage deletes the targeted message from storage. Users may delete
	// their own messages but only the channel admin can delete other user's
	// messages. If the user is not an admin of the channel or if they are not
	// the sender of the targetMessage, then the error NotAnAdminErr is
	// returned.
	//
	// Clients will drop the deletion if they do not recognize the target
	// message.
	DeleteMessage(channelID *id.ID, targetMessage message.ID,
		params cmix.CMIXParams) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// PinMessage pins the target message to the top of a channel view for all
	// users in the specified channel. Only the channel admin can pin user
	// messages; if the user is not an admin of the channel, then the error
	// NotAnAdminErr is returned.
	//
	// If undoAction is true, then the targeted message is unpinned. validUntil
	// is the time the message will be pinned for; set this to ValidForever to
	// pin indefinitely. validUntil is ignored if undoAction is true.
	//
	// Clients will drop the pin if they do not recognize the target message.
	PinMessage(channelID *id.ID, targetMessage message.ID,
		undoAction bool, validUntil time.Duration, params cmix.CMIXParams) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// MuteUser is used to mute a user in a channel. Muting a user will cause
	// all future messages from the user being dropped on reception. Muted users
	// are also unable to send messages. Only the channel admin can mute a user;
	// if the user is not an admin of the channel, then the error NotAnAdminErr
	// is returned.
	//
	// If undoAction is true, then the targeted user will be unmuted. validUntil
	// is the time the user will be muted for; set this to ValidForever to mute
	// the user indefinitely. validUntil is ignored if undoAction is true.
	MuteUser(channelID *id.ID, mutedUser ed25519.PublicKey, undoAction bool,
		validUntil time.Duration, params cmix.CMIXParams) (
		message.ID, rounds.Round, ephemeral.Id, error)

	// GetIdentity returns the public identity of the user associated with this
	// channel manager.
	GetIdentity() cryptoChannel.Identity

	// ExportPrivateIdentity encrypts the private identity using the password
	// and exports it to a portable string.
	ExportPrivateIdentity(password string) ([]byte, error)

	// GetStorageTag returns the tag where this manager is stored. To be used
	// when loading the manager. The storage tag is derived from the public key.
	GetStorageTag() string

	// RegisterReceiveHandler registers a listener for non-default message types
	// so that they can be processed by modules. It is important that such
	// modules collective up with the event model implementation.
	//
	// There can only be one handler per message type; the error
	// MessageTypeAlreadyRegistered will be returned on multiple registrations
	// of the same type.
	//
	// To create a ReceiveMessageHandler, use NewReceiveMessageHandler.
	RegisterReceiveHandler(
		messageType MessageType, handler *ReceiveMessageHandler) error

	// SetNickname sets the nickname in a channel after checking that the
	// nickname is valid using [IsNicknameValid].
	SetNickname(nickname string, channelID *id.ID) error

	// DeleteNickname removes the nickname for a given channel. The name will
	// revert back to the codename for this channel instead.
	DeleteNickname(channelID *id.ID) error

	// GetNickname returns the nickname for the given channel, if it exists.
	GetNickname(channelID *id.ID) (nickname string, exists bool)

	// Muted returns true if the user is currently muted in the given channel.
	Muted(channelID *id.ID) bool

	// GetMutedUsers returns the list of the public keys for each muted user in
	// the channel. If there are no muted user or if the channel does not exist,
	// an empty list is returned.
	GetMutedUsers(channelID *id.ID) []ed25519.PublicKey

	// GetNotificationLevel returns the notification level for the given channel.
	GetNotificationLevel(channelID *id.ID) (NotificationLevel, error)

	// GetNotificationStatus returns the notification status for the given channel.
	GetNotificationStatus(channelID *id.ID) (clientNotif.NotificationState, error)

	// SetMobileNotificationsLevel sets the notification level for the given
	// channel. The [NotificationLevel] dictates the type of notifications
	// received and the status controls weather the notification is push or
	// in-app. If muted, both the level and status must be set to mute.
	//
	// To use push notifications, a token must be registered with the
	// notification manager. Note, when enabling push notifications, information
	// may be shared with third parties (i.e., Firebase and Google's Palantir)
	// and may represent a security risk to the user.
	SetMobileNotificationsLevel(channelID *id.ID, level NotificationLevel,
		status clientNotif.NotificationState) error

	// IsChannelAdmin returns true if the user is an admin of the channel.
	IsChannelAdmin(channelID *id.ID) bool

	// ExportChannelAdminKey gets the private key for the given channel ID,
	// encrypts it with the provided encryptionPassword, and exports it into a
	// portable format. Returns an error if the user is not an admin of the
	// channel.
	//
	// This key can be provided to other users in a channel to grant them admin
	// access using ImportChannelAdminKey.
	//
	// The private key is encrypted using a key generated from the password
	// using Argon2. Each call to ExportChannelAdminKey produces a different
	// encrypted packet regardless if the same password is used for the same
	// channel. It cannot be determined which channel the payload is for nor
	// that two payloads are for the same channel.
	//
	// The passwords between each call are not related. They can be the same or
	// different with no adverse impact on the security properties.
	ExportChannelAdminKey(
		channelID *id.ID, encryptionPassword string) ([]byte, error)

	// VerifyChannelAdminKey verifies that the encrypted private key can be
	// decrypted and that it matches the expected channel. Returns false if
	// private key does not belong to the given channel.
	//
	// Returns the error WrongPasswordErr for an invalid password. Returns the
	// error ChannelDoesNotExistsErr if the channel has not already been joined.
	VerifyChannelAdminKey(
		channelID *id.ID, encryptionPassword string, encryptedPrivKey []byte) (
		bool, error)

	// ImportChannelAdminKey decrypts and imports the given encrypted private
	// key and grants the user admin access to the channel the private key
	// belongs to. Returns an error if the private key cannot be decrypted or if
	// the private key is for the wrong channel.
	//
	// Returns the error WrongPasswordErr for an invalid password. Returns the
	// error ChannelDoesNotExistsErr if the channel has not already been joined.
	// Returns the error WrongPrivateKeyErr if the private key does not belong
	// to the channel.
	ImportChannelAdminKey(channelID *id.ID, encryptionPassword string,
		encryptedPrivKey []byte) error

	// DeleteChannelAdminKey deletes the private key for the given channel.
	//
	// CAUTION: This will remove admin access. This cannot be undone. If the
	// private key is deleted, it cannot be recovered and the channel can never
	// have another admin.
	DeleteChannelAdminKey(channelID *id.ID) error
}

Manager provides an interface to manager channels.

func LoadManager

func LoadManager(storageTag string, kv versioned.KV, net Client,
	rng *fastRNG.StreamGenerator, model EventModel,
	extensions []ExtensionBuilder, nm NotificationsManager,
	uiCallbacks UiCallbacks) (Manager, error)

LoadManager restores a channel Manager from disk stored at the given storage tag.

func LoadManagerBuilder added in v4.5.0

func LoadManagerBuilder(storageTag string, kv versioned.KV, net Client,
	rng *fastRNG.StreamGenerator, modelBuilder EventModelBuilder,
	extensions []ExtensionBuilder, nm NotificationsManager,
	uiCallbacks UiCallbacks) (Manager, error)

LoadManagerBuilder restores a channel Manager from disk stored at the given storage tag.

func NewManager

func NewManager(identity cryptoChannel.PrivateIdentity, kv versioned.KV,
	net Client, rng *fastRNG.StreamGenerator, model EventModel,
	extensions []ExtensionBuilder, addService AddServiceFn,
	nm NotificationsManager, uiCallbacks UiCallbacks) (Manager, error)

NewManager creates a new channel Manager from a cryptoChannel.PrivateIdentity. It prefixes the KV with a tag derived from the public key that can be retried for reloading using [Manager.GetStorageTag].

func NewManagerBuilder added in v4.5.0

func NewManagerBuilder(identity cryptoChannel.PrivateIdentity, kv versioned.KV,
	net Client, rng *fastRNG.StreamGenerator, modelBuilder EventModelBuilder,
	extensions []ExtensionBuilder, addService AddServiceFn,
	nm NotificationsManager, uiCallbacks UiCallbacks) (Manager, error)

NewManagerBuilder creates a new channel Manager using an EventModelBuilder.

type MessageType

type MessageType uint16

MessageType is the type of message being sent to a channel.

const (

	// Text is the default type for a message. It denotes that the message only
	// contains text.
	Text MessageType = 1

	// AdminText denotes that the message only contains text and that it comes
	// from the channel admin.
	AdminText MessageType = 2

	// Reaction denotes that the message is a reaction to another message.
	Reaction MessageType = 3

	// Silent denotes that the message is a silent message which should not
	// notify the user in any way.
	Silent MessageType = 4

	// Invitation denotes that the message is an invitation to another channel.
	Invitation MessageType = 5

	// Delete denotes that the message should be deleted. It is removed from the
	// database and deleted from the user's view.
	Delete MessageType = 101

	// Pinned denotes that the message should be pinned to the channel.
	Pinned MessageType = 102

	// Mute denotes that any future messages from the user are hidden. The
	// messages are still received, but they are not visible.
	Mute MessageType = 103

	// AdminReplay denotes that the message contains an admin message.
	AdminReplay MessageType = 104

	// FileTransfer denotes that a message contains the information about a file
	// download.
	FileTransfer MessageType = 40000
)

func UnmarshalMessageType added in v4.7.1

func UnmarshalMessageType(b [2]byte) MessageType

UnmarshalMessageType returns the MessageType from its byte representation.

func (MessageType) Bytes added in v4.4.4

func (mt MessageType) Bytes() []byte

Bytes returns the MessageType as a 2-byte byte slice.

func (MessageType) Marshal added in v4.7.1

func (mt MessageType) Marshal() [2]byte

Marshal returns the byte representation of the MessageType.

func (MessageType) String

func (mt MessageType) String() string

String returns a human-readable version of MessageType, used for debugging and logging. This function adheres to the fmt.Stringer interface.

type MessageTypeReceiveMessage

type MessageTypeReceiveMessage func(channelID *id.ID, messageID message.ID,
	messageType MessageType, nickname string, content, encryptedPayload []byte,
	pubKey ed25519.PublicKey, dmToken uint32, codeset uint8, timestamp,
	originatingTimestamp time.Time, lease time.Duration,
	originatingRound id.Round, round rounds.Round, status SentStatus, fromAdmin,
	hidden bool) uint64

MessageTypeReceiveMessage defines handlers for messages of various message types. Default ones for Text, Reaction, and AdminText.

A unique UUID must be returned by which the message can be referenced later via [EventModel.UpdateFromUUID].

If fromAdmin is true, then the message has been verified to come from the channel admin.

type ModelMessage added in v4.4.4

type ModelMessage struct {
	UUID            uint64            `json:"uuid"`
	Nickname        string            `json:"nickname"`
	MessageID       message.ID        `json:"messageID"`
	ChannelID       *id.ID            `json:"channelID"`
	ParentMessageID message.ID        `json:"parentMessageID"`
	Timestamp       time.Time         `json:"timestamp"`
	Lease           time.Duration     `json:"lease"`
	Status          SentStatus        `json:"status"`
	Hidden          bool              `json:"hidden"`
	Pinned          bool              `json:"pinned"`
	Content         []byte            `json:"content"`
	Type            MessageType       `json:"type"`
	Round           id.Round          `json:"round"`
	PubKey          ed25519.PublicKey `json:"pubKey"`
	CodesetVersion  uint8             `json:"codesetVersion"`
	DmToken         uint32            `json:"dmToken"`
}

ModelMessage contains a message and all of its information.

type NameService

type NameService interface {
	// GetUsername returns the username.
	GetUsername() string

	// GetChannelValidationSignature returns the validation signature and the
	// time it was signed.
	GetChannelValidationSignature() ([]byte, time.Time)

	// GetChannelPubkey returns the user's public key.
	GetChannelPubkey() ed25519.PublicKey

	// SignChannelMessage returns the signature of the given message.
	SignChannelMessage(message []byte) (signature []byte, err error)

	// ValidateChannelMessage validates that a received channel message's
	// username lease is signed by the NameService.
	ValidateChannelMessage(username string, lease time.Time,
		pubKey ed25519.PublicKey, authorIDSignature []byte) bool
}

NameService is an interface which encapsulates the user identity channel tracking service.

NameService is currently unused.

func NewDummyNameService

func NewDummyNameService(username string, rng io.Reader) (NameService, error)

NewDummyNameService returns a dummy object adhering to the name service. This neither produces valid signatures nor validates passed signatures.

THIS IS FOR DEVELOPMENT AND DEBUGGING PURPOSES ONLY.

type NotificationCallback added in v4.7.1

type NotificationCallback func(nfs []NotificationFilter,
	changedNotificationStates []NotificationState,
	deletedNotificationStates []*id.ID, maxState clientNotif.NotificationState)

NotificationCallback is a callback that is called any time a notification level changes.

It returns a slice of NotificationFilter for all channels with notifications enabled. The NotificationFilter is used to determine which notifications from the notification server belong to the caller.

It also returns a map of all channel notification states that have changed and all that have been deleted. The maxState is the global state set for notifications.

type NotificationFilter added in v4.7.1

type NotificationFilter struct {
	Identifier []byte `json:"identifier"`

	// ChannelID is the ID that the filter belongs to.
	ChannelID *id.ID `json:"channelID"`

	// Tags is a list of tags to match against.
	Tags []string `json:"tags"`

	AllowLists `json:"allowLists"`
}

NotificationFilter defines filtering properties for channel message notifications.

These will be tested against every received notification. The notification, which is encrypted, will not be decrypted properly unless the identifier is correct. As a result, the identifier will be tested against a garbled message and the probability of false collisions is simply the random chance that all bloom bits are flipped.

Given that K = 26 (see elixxir/crypto/sih/evaluatable.go), the collision chance is 1/2^26. The message types would also need to collide given that in the 16-bit space there are only expected to be a small number of messages that are valid notifications, the collision chance increases by ~20/2^16.

Given this information, the number of evaluations where a user has a 50% chance of a false notification can be calculated as (x = ln(.5)/ln(1-p)) where p = (1/2^26) * (1/2^10), x = 1.5 * 10^11, assuming a user is registered in 100 channels and received 100,000 total notifications a day, this number of events would occur after 15,243 days, which is the mean time to false notification through this system. This number is very acceptable.

type NotificationInfo added in v4.7.1

type NotificationInfo struct {
	Status   bool   `json:"status"`
	Metadata []byte `json:"metadata"`
}

NotificationInfo contains notification information for each identity.

type NotificationLevel added in v4.7.1

type NotificationLevel uint8

NotificationLevel specifies what level of notifications should be received for a channel.

const (
	// NotifyNone results in no notifications.
	NotifyNone NotificationLevel = 10

	// NotifyPing results in notifications from tags, replies, and pins.
	NotifyPing NotificationLevel = 20

	// NotifyAll results in notifications from all messages except silent ones
	// and replays.
	NotifyAll NotificationLevel = 40
)

func UnmarshalNotificationLevel added in v4.7.1

func UnmarshalNotificationLevel(b []byte) NotificationLevel

UnmarshalNotificationLevel unmarshalls the byte slice into a NotificationLevel.

func (NotificationLevel) Marshal added in v4.7.1

func (nl NotificationLevel) Marshal() []byte

Marshal returns the byte representation of the NotificationLevel.

func (NotificationLevel) String added in v4.7.1

func (nl NotificationLevel) String() string

String prints a human-readable form of the NotificationLevel for logging and debugging. This function adheres to the fmt.Stringer interface.

type NotificationReport added in v4.7.1

type NotificationReport struct {
	// Channel is the channel ID that the notification is for.
	Channel *id.ID `json:"channel"`

	// Type is the MessageType of the message that the notification belongs to.
	Type MessageType `json:"type"`

	// PingType describes the type of ping. If it is empty, then it is a generic
	// ping.
	PingType PingType `json:"pingType,omitempty"`
}

NotificationReport describes information about a single notification belonging to the user.

func GetNotificationReportsForMe added in v4.7.1

func GetNotificationReportsForMe(nfs []NotificationFilter,
	notificationData []*primNotif.Data) []NotificationReport

GetNotificationReportsForMe checks the notification data against the filter list to determine which notifications belong to the user. A list of notification reports is returned detailing all notifications for the user.

type NotificationState added in v4.7.1

type NotificationState struct {
	ChannelID *id.ID                        `json:"channelID"`
	Level     NotificationLevel             `json:"level"`
	Status    clientNotif.NotificationState `json:"status"`
}

NotificationState contains information about the notifications for a channel.

type NotificationsManager added in v4.7.1

type NotificationsManager interface {
	Set(toBeNotifiedOn *id.ID, group string, metadata []byte,
		status clientNotif.NotificationState) error
	Get(toBeNotifiedOn *id.ID) (status clientNotif.NotificationState,
		metadata []byte, group string, exists bool)
	Delete(toBeNotifiedOn *id.ID) error
	RegisterUpdateCallback(group string, nu clientNotif.Update)
}

NotificationsManager contains the methods from [notifications.Manager] that are required by the Manager.

type PingType added in v4.7.1

type PingType string

PingType describes a user ping. It is used to describe more information about the ping to the user.

const (
	// GenericPing indicates a generic notification that is not a reply or
	// mention.
	GenericPing PingType = ""

	// ReplyPing indicates that someone replied to this user's message.
	ReplyPing PingType = "usrReply"

	// MentionPing indicates that someone mentioned (tagged) the user in a
	// message.
	MentionPing PingType = "usrMention"
)

type ReceiveMessageHandler added in v4.4.4

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

ReceiveMessageHandler contains a message listener MessageTypeReceiveMessage linked to a specific MessageType. It also lists which spaces this handler can receive messages for.

func NewReceiveMessageHandler added in v4.4.4

func NewReceiveMessageHandler(name string, listener MessageTypeReceiveMessage,
	userSpace, adminSpace, mutedSpace bool) *ReceiveMessageHandler

NewReceiveMessageHandler generates a new ReceiveMessageHandler.

Parameters:

  • name - A name describing what type of messages the listener picks up. This is used for debugging and logging.
  • listener - The listener that handles the received message.
  • userSpace - Set to true if this listener can receive messages from normal users.
  • adminSpace - Set to true if this listener can receive messages from admins.
  • mutedSpace - Set to true if this listener can receive messages from muted users.

func (*ReceiveMessageHandler) CheckSpace added in v4.4.4

func (rmh *ReceiveMessageHandler) CheckSpace(user, admin, muted bool) error

CheckSpace checks that ReceiveMessageHandler can receive in the given user spaces. Returns nil if the message matches one or more of the handler's spaces. Returns an error if it does not.

func (*ReceiveMessageHandler) SpaceString added in v4.4.4

func (rmh *ReceiveMessageHandler) SpaceString() string

SpaceString returns a string with the values of each space. This is used for logging and debugging purposes.

type ReplayActionFunc added in v4.4.4

type ReplayActionFunc func(channelID *id.ID, encryptedPayload []byte)

ReplayActionFunc replays the encrypted payload on the channel.

type SentStatus

type SentStatus uint8

SentStatus represents the current status of a channel message.

const (
	// Unsent is the status of a message when it is pending to be sent.
	Unsent SentStatus = 0

	// Sent is the status of a message once the round it is sent on completed.
	Sent SentStatus = 1

	// Delivered is the status of a message once is has been received.
	Delivered SentStatus = 2

	// Failed is the status of a message if it failed to send.
	Failed SentStatus = 3
)

func (SentStatus) String

func (ss SentStatus) String() string

String returns a human-readable version of SentStatus, used for debugging and logging. This function adheres to the fmt.Stringer interface.

type UiCallbacks added in v4.7.1

type UiCallbacks interface {
	// NicknameUpdate is called when your nickname changes due to a
	// change on a remote.
	NicknameUpdate(channelId *id.ID, nickname string, exists bool)

	// NotificationUpdate is a callback that is called any time a notification
	// level changes. It is also called when loading, adding, and deleting
	// channels.
	//
	// It returns a slice of [NotificationFilter] for all channels with
	// notifications enabled. The [NotificationFilter] is used to determine
	// which notifications from the notification server belong to the caller.
	//
	// It also returns a map of all channel notification states that have
	// changed and all that have been deleted. The maxState is the global state
	// set for notifications.
	NotificationUpdate(nfs []NotificationFilter,
		changedNotificationStates []NotificationState,
		deletedNotificationStates []*id.ID, maxState clientNotif.NotificationState)

	// AdminKeysUpdate is a callback be called when a channel's admin key is
	// added or removed. (See [Manager.ImportChannelAdminKey] or
	// [Manager.DeleteChannelAdminKey]).
	AdminKeysUpdate(chID *id.ID, isAdmin bool)

	// DmTokenUpdate is a callback be called when a channel's dm token state is
	// changed
	DmTokenUpdate(chID *id.ID, sendToken bool)

	// ChannelUpdate is called any time the user joins or leaves a channel.
	// deleted is false when joining and true when leaving.
	ChannelUpdate(channelID *id.ID, deleted bool)

	// MessageReceived is called any time a new message is received or an
	// existing message is modified. update is ture when the message is
	// modified. It is false when receiving a new message.
	MessageReceived(uuid int64, channelID *id.ID, update bool)

	// UserMuted is called every time a user is muted or unmuted.
	UserMuted(channelID *id.ID, pubKey ed25519.PublicKey, unmute bool)

	// MessageDeleted is called every time a message is deleted.
	MessageDeleted(messageID message.ID)
}

UiCallbacks is an interface that a caller can adhere to in order to get updates on when sync events occur that require the UI to be updated and what those events are.

type UpdateActionFn added in v4.6.3

type UpdateActionFn func() (uint64, error)

UpdateActionFn updates a message if it has a saved action. It returns a UUID and an error

type UpdateFromUuidFunc added in v4.4.4

type UpdateFromUuidFunc func(uuid uint64, messageID *message.ID,
	timestamp *time.Time, round *rounds.Round, pinned, hidden *bool,
	status *SentStatus) error

UpdateFromUuidFunc is a function type for EventModel.UpdateFromUUID so it can be mocked for testing where used.

type UserMessage

type UserMessage struct {

	// Message contains the contents of the message. This is typically what the
	// end-user has submitted to the channel. This is a serialization of the
	// ChannelMessage.
	Message []byte `protobuf:"bytes,1,opt,name=Message,proto3" json:"Message,omitempty"`
	// Signature is the signature proving this message has been sent by the
	// owner of this user's public key.
	//
	//	Signature = Sig(User_ECCPublicKey, Message)
	Signature []byte `protobuf:"bytes,3,opt,name=Signature,proto3" json:"Signature,omitempty"`
	// ECCPublicKey is the user's EC Public key. This is provided by the
	// network.
	ECCPublicKey []byte `protobuf:"bytes,5,opt,name=ECCPublicKey,proto3" json:"ECCPublicKey,omitempty"`
	// contains filtered or unexported fields
}

UserMessage is a message sent by a user who is a member within the channel.

func (*UserMessage) Descriptor deprecated

func (*UserMessage) Descriptor() ([]byte, []int)

Deprecated: Use UserMessage.ProtoReflect.Descriptor instead.

func (*UserMessage) GetECCPublicKey

func (x *UserMessage) GetECCPublicKey() []byte

func (*UserMessage) GetMessage

func (x *UserMessage) GetMessage() []byte

func (*UserMessage) GetSignature

func (x *UserMessage) GetSignature() []byte

func (*UserMessage) ProtoMessage

func (*UserMessage) ProtoMessage()

func (*UserMessage) ProtoReflect

func (x *UserMessage) ProtoReflect() protoreflect.Message

func (*UserMessage) Reset

func (x *UserMessage) Reset()

func (*UserMessage) String

func (x *UserMessage) String() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL