client

package
v0.3.8 Latest Latest
Warning

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

Go to latest
Published: Aug 14, 2026 License: BSD-3-Clause Imports: 18 Imported by: 0

Documentation

Overview

Package client is a high-level Olvid client abstraction built on the engine (crypto/protocols) and the server API. A Session ties an owned identity and its device to a server, manages the authentication token, and sends/receives application messages over the live network via the asymmetric channel.

This is the foundation for a full Olvid client: it handles the message lifecycle (build → encrypt → upload; download → decrypt → delete). Oblivious channels, groups, and the protocol state machines can be layered on top.

Index

Constants

View Source
const (
	CallStart     = 0
	CallAnswer    = 1
	CallReject    = 2
	CallHangedUp  = 3
	CallRinging   = 4
	CallBusy      = 5
	CallReconnect = 6
)

Call signaling message types (spec §38, Table 4).

View Source
const (
	SDPTypeOffer    = "offer"
	SDPTypePranswer = "pranswer"
)

Session description types (spec §39.2): "offer" for start/reconnect, "pranswer" for answer.

View Source
const (
	TrustDirect        = 1 // direct SAS mutual trust ("one-to-one")
	TrustIntroduction  = 2 // introduced by a mediator contact
	TrustGroup         = 3 // legacy (v1) owned-group membership
	TrustKeycloak      = 4 // vouched by an identity (keycloak) server
	TrustServerGroupV2 = 5 // membership of a shared groups-v2 group
)

Trust-origin types, matching the reference (io.olvid.engine.identity.databases.ContactTrustOrigin): how a contact first became trusted. The live library only ever produces TrustDirect (a SAS mutual-trust exchange) and TrustServerGroupV2 (learned as a member of a shared group); the others are defined for parity with restored/interop backups.

View Source
const (
	LocationTypeSend       = 1
	LocationTypeSharing    = 2
	LocationTypeEndSharing = 3
)

Location message types (spec §22.2, "Location information").

View Source
const MaxAttachmentBytes int64 = 2 << 30 // 2 GiB

DownloadAttachmentTo streams a received attachment: it downloads each chunk, decrypts it, and writes the plaintext to w in order (peak memory ≈ one chunk), so it scales to large files (spec §23.3, §45.1). key comes from the message's decoded attachment descriptor (engine.DecodeAttachmentDescriptor). MaxAttachmentBytes bounds a single received attachment the library will download. The size and the chunk count come from the message listing, which is derived from the SENDER's declared upload — so without a cap a malicious contact could declare an enormous attachment and OOM/fill-disk a recipient who downloads it. Front-ends may enforce a stricter limit of their own.

Variables

View Source
var AttachmentChunkDataSize = 2 << 20 // 2 MiB

AttachmentChunkDataSize is the plaintext size of each attachment chunk (the encrypted chunk is a little larger, spec §23.3). It is a variable so tests can exercise multi-chunk attachments with small content.

Functions

func DecodeApplicationMessage

func DecodeApplicationMessage(plaintext []byte) (payloadJSON []byte, err error)

DecodeApplicationMessage reverses EncodeApplicationMessage, returning the message-payload JSON. It errors on non-application messages.

func DecodeApplicationMessageAttachments

func DecodeApplicationMessageAttachments(plaintext []byte) (payloadJSON []byte, descriptors [][]byte, err error)

DecodeApplicationMessageAttachments returns the payload JSON and the raw attachment descriptors from an application-message plaintext.

func EncodeApplicationMessage

func EncodeApplicationMessage(payloadJSON []byte) []byte

EncodeApplicationMessage wraps a serialized message-payload JSON into the encoded application-message plaintext ready for SendMessage.

func EncodeApplicationMessageWithAttachments

func EncodeApplicationMessageWithAttachments(payloadJSON []byte, descriptors [][]byte) []byte

EncodeApplicationMessageWithAttachments builds the application-message plaintext with n attachment descriptors followed by the payload JSON (spec §22.2). Each descriptor is an engine.EncodeAttachmentDescriptor result.

func EncodeApplicationPayload

func EncodeApplicationPayload(p *MessagePayload) ([]byte, error)

EncodeApplicationPayload marshals the payload and wraps it into the encoded application-message plaintext ready for SendMessage (spec §22.2).

func GunzipSDP

func GunzipSDP(gzipped []byte) ([]byte, error)

GunzipSDP decompresses an SDP blob from the "sd" field, rejecting oversized output.

func GzipSDP

func GzipSDP(sdp []byte) ([]byte, error)

GzipSDP compresses an SDP blob for the "sd" field (spec §38).

func IsTrustEstablishmentRequest

func IsTrustEstablishmentRequest(pm *engine.ProtocolMessage) bool

IsTrustEstablishmentRequest reports whether an inbound protocol message (from OnProtocolMessage) is a peer initiating trust toward us (a SAS commitment) — pass it to ProcessTrustEstablishment to start a responder.

func IsTrustEstablishmentSASMessage added in v0.2.5

func IsTrustEstablishmentSASMessage(pm *engine.ProtocolMessage) bool

IsTrustEstablishmentSASMessage reports whether an inbound protocol message belongs to the SAS Trust Establishment protocol at all (commitment, seed, decommitment or confirmation), so a caller can route it by instance UID to the matching in-flight exchange and drive several concurrently.

func OpenInteropBackup

func OpenInteropBackup(seed engine.BackupSeed, blob []byte) (*engine.BackupJSON, error)

OpenInteropBackup decrypts and parses an Olvid-interop backup under seed. It errors if the backup is not the interop format.

func ParseInvitationLink(link string) (*engine.ObvURLIdentity, error)

ParseInvitationLink exposes the engine's invitation-link parser at the client boundary.

func RestoreOwnedIdentityFromBackup

func RestoreOwnedIdentityFromBackup(b *engine.BackupJSON) (*engine.OwnedCryptoIdentity, error)

RestoreOwnedIdentityFromBackup rebuilds the owned identity from the first owned-identity node of a decrypted interop backup (spec §37). The caller then assigns a fresh random device UID and constructs a Session with the returned identity.

func SerializeGroupName

func SerializeGroupName(name string) string

SerializeGroupName builds a minimal JsonGroupDetails JSON string with the given name — the group's serialized details, the counterpart of Group.Name.

func SerializeGroupNameAndDescription

func SerializeGroupNameAndDescription(name, description string) string

SerializeGroupNameAndDescription builds a JsonGroupDetails JSON string with a name and description (the description is omitted when empty). Pass the result to CreateGroup or UpdateGroupDetails.

func SerializeGroupType

func SerializeGroupType(t string) string

SerializeGroupType renders a JsonGroupType (reference io.olvid…types.JsonGroupType). Valid types are "simple", "private", and "read_only"; "simple" (everyone posts, admins manage) is the sensible default for a gateway-created group. An empty type is omitted from the blob (a typeless group), which some clients render poorly — prefer an explicit type.

Types

type AnswerCallMessage

type AnswerCallMessage struct {
	SessionDescriptionType string `json:"sdt"`
	GzippedSDP             []byte `json:"sd"`
}

AnswerCallMessage answers a call (mt=CallAnswer) with the pranswer SDP.

type BackupOptions

type BackupOptions struct {
	PublishedDetails engine.IdentityDetailsBackup
	LatestDetails    engine.IdentityDetailsBackup
	APIKey           string
	// Contacts and GroupsV2 are the real contact/group data to include in an interop
	// backup. GroupsV2 are the caller's live groups (their Blob/Keys/OwnNonce are read).
	// Both are ignored for the library format.
	Contacts []ContactBackupInput
	GroupsV2 []*Group
	// Snapshot, when set, is backed up in the library format instead of a default
	// settings snapshot. Ignored for the interop format.
	Snapshot *engine.Snapshot
	// TimestampMillis stamps the interop backup (unix millis). Pass a real clock value;
	// 0 is acceptable for tests.
	TimestampMillis int64
}

BackupOptions carries the extra data the interop JSON needs beyond the owned identity (details, api key). It is ignored for the library format.

type CallMessage

type CallMessage struct {
	CallIdentifier string
	MessageType    int
	Payload        []byte // the raw "smp" JSON
}

CallMessage is a parsed inbound call-signaling message. Decode Payload into the matching struct based on MessageType (e.g. ParseStartCall for CallStart).

func (*CallMessage) ParseAnswerCall

func (m *CallMessage) ParseAnswerCall() (*AnswerCallMessage, error)

func (*CallMessage) ParseMuted

func (m *CallMessage) ParseMuted() (*MutedMessage, error)

func (*CallMessage) ParseReconnectCall

func (m *CallMessage) ParseReconnectCall() (*ReconnectCallMessage, error)

func (*CallMessage) ParseStartCall

func (m *CallMessage) ParseStartCall() (*StartCallMessage, error)

ParseStartCall / ParseAnswerCall / ParseReconnectCall / ParseMuted decode the Payload of a CallMessage into its typed form.

type ChannelCreation

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

ChannelCreation drives one party of the Channel Creation protocol over the network.

func (*ChannelCreation) Channel

func (cc *ChannelCreation) Channel() *engine.ObliviousChannel

Channel returns the established oblivious channel (nil until Done).

func (*ChannelCreation) Done

func (cc *ChannelCreation) Done() bool

Done reports whether the channel has been confirmed and registered.

func (*ChannelCreation) Pump

func (cc *ChannelCreation) Pump() (done bool, err error)

Pump downloads pending messages, feeds the protocol ones to the party, and uploads any replies. It deletes messages the protocol consumed; messages the protocol cannot use (application messages, other protocols) are left on the server. Returns true once the channel is confirmed. Call repeatedly.

type ChannelDeleter

type ChannelDeleter interface {
	DeleteChannel(deviceUID []byte) error
}

ChannelDeleter is an optional ChannelStore capability: removing a persisted channel (so removing a contact also frees its channel rows). The store package implements it.

type ChannelStore

type ChannelStore interface {
	SaveChannel(contactDeviceUID, encoded []byte) error
}

ChannelStore persists oblivious-channel ratchet state. Implemented by the store package.

type Contact

type Contact struct {
	Identity          *engine.CryptoIdentity
	DisplayName       string
	PublishedDetails  string        // serialized identity details (JSON), as published by the contact
	TrustedDetails    string        // serialized identity details we currently trust
	TrustLevel        string        // Olvid trust level string, e.g. "0.4"
	OneToOne          bool          // a one-to-one (direct) contact
	Revoked           bool          // revoked as compromised
	ForcefullyTrusted bool          // trust forced by the user despite revocation
	DeviceUIDs        [][]byte      // known device UIDs, for addressing messages
	Capabilities      []string      // advertised capabilities (e.g. groups-v2, one-to-one contacts)
	TrustOrigins      []TrustOrigin // how this contact came to be trusted (accumulated, oldest first)
	DetailsVersion    int           // version of the last published details we accepted (rejects stale updates)
}

Contact is the library's first-class handle for a remote identity: it bundles the crypto identity with the device UIDs needed to address it and the trust/detail metadata a client maintains. Calls that would otherwise take (identity, deviceUIDs) can take a *Contact instead (see the *ToContact convenience methods). A Session owns its contacts in memory and, when a ContactStore is configured, persists them (see AddContact, Contacts, Restore).

The fields are "backup-grade": they carry everything the interop backup's contact_identities entry needs, so a stored contact set can be backed up and restored.

func DecodeContact

func DecodeContact(b []byte) (*Contact, error)

DecodeContact reverses Contact.Encode.

func (*Contact) Encode

func (c *Contact) Encode() []byte

Encode serializes a contact for local persistence (not a wire format).

func (*Contact) IdentityBytes

func (c *Contact) IdentityBytes() []byte

IdentityBytes returns the contact's raw identity bytes.

type ContactBackupInput

type ContactBackupInput struct {
	Identity          *engine.CryptoIdentity
	PublishedDetails  engine.IdentityDetailsBackup
	TrustedDetails    engine.IdentityDetailsBackup
	TrustLevel        string
	TrustOrigins      []engine.ContactTrustOrigin
	OneToOne          bool
	Revoked           bool
	ForcefullyTrusted bool
}

ContactBackupInput is a contact to include in an interop backup. The library keeps no contact database, so the caller supplies each contact's data; identity and details are stored, and a restore re-establishes the rest via device discovery (spec §37).

type ContactMgmtEvent added in v0.3.0

type ContactMgmtEvent int

ContactMgmtEvent names what an inbound contact-management message did, for the caller to surface.

const (
	ContactMgmtNone       ContactMgmtEvent = iota
	ContactMgmtDeleted                     // the contact (or our own device) removed this contact
	ContactMgmtDowngraded                  // the contact (or our own device) downgraded this contact
)

type ContactStore

type ContactStore interface {
	SaveContactBlob(identity, encoded []byte) error
	LoadContactBlobs() ([][]byte, error)
	DeleteContact(identity []byte) error
}

ContactStore persists contacts. Implemented by the store package. Keys are raw identity bytes; values are Contact.Encode() blobs (the store handles at-rest encryption).

type DeleteDiscussion

type DeleteDiscussion struct {
	GroupUID           []byte              `json:"guid,omitempty"`
	GroupOwner         []byte              `json:"go,omitempty"`
	GroupV2Identifier  []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier *OneToOneIdentifier `json:"o2oi,omitempty"`
}

DeleteDiscussion "deletes everywhere" a whole discussion (spec §22.2, "Discussion delete request").

type DeleteMessages

type DeleteMessages struct {
	GroupUID           []byte              `json:"guid,omitempty"`
	GroupOwner         []byte              `json:"go,omitempty"`
	GroupV2Identifier  []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier *OneToOneIdentifier `json:"o2oi,omitempty"`
	References         []MessageReference  `json:"refs,omitempty"`
}

DeleteMessages "deletes everywhere" a set of messages in one discussion (spec §22.2, "Messages delete request").

type DeviceTransfer

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

DeviceTransfer drives the joining (target) side of an owned-identity transfer: it dials the relay, joins the session, exchanges the handshake, and — after the user confirms the SAS on the existing device — receives the snapshot and restores it. Construct it with JoinAsDevice.

func JoinAsDevice

func JoinAsDevice(srv *server.Client, wsURL, sessionNumber, deviceName string, serverURL []byte, rnd prng.PRNG) (*DeviceTransfer, error)

JoinAsDevice starts joining an existing Olvid profile as a new device. It dials the transfer relay (wsURL, e.g. server.TransferServerURL), joins by the session number the existing device shows, and drives the handshake to the SAS. On return, dt.SAS() holds the 8 digits to DISPLAY; the user enters them on the existing device, then Restore() receives the snapshot and builds the session. serverURL seeds the throwaway ephemeral identity (cosmetic); deviceName labels this device.

func (*DeviceTransfer) Close

func (dt *DeviceTransfer) Close() error

Close aborts an in-progress transfer.

func (*DeviceTransfer) KeepActiveDevice added in v0.2.1

func (dt *DeviceTransfer) KeepActiveDevice() []byte

KeepActiveDevice returns the device UID the source designated to keep active (single-device / device-limited profiles), or nil. It is known only after Restore. After Register(), the joining device should call Session.SetDeviceNonExpiring on it so the server does not expire the operator-chosen device under a multi-device limit (reference OwnedIdentityTransferProtocol: SetUnexpiringDevice on deviceUidToKeepActive; iOS requestServerToKeepDeviceActive).

func (*DeviceTransfer) Restore

func (dt *DeviceTransfer) Restore(st RestoreStore, opts ...Option) (*Session, error)

Restore blocks until the existing device sends the snapshot (which it does only after the user confirms the SAS matched), then builds the co-device session in st. Follow with sess.Register() and sess.ResyncAfterRestore(). Closes the relay connection.

func (*DeviceTransfer) SAS

func (dt *DeviceTransfer) SAS() string

SAS returns the 8 digits to display; the user enters them on the existing device to authorise the transfer.

type DeviceTransferSource

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

DeviceTransferSource drives the existing-device (source) side: it opens a session, waits for a joining device, exchanges the handshake, and — after the user confirms the SAS — sends the snapshot. Construct it with OfferDeviceTransfer. (The primary gateway use is the target side; this is provided for completeness and testing.)

func OfferDeviceTransfer

func OfferDeviceTransfer(srv *server.Client, wsURL string, owned *engine.OwnedCryptoIdentity, snapshot []byte, rnd prng.PRNG) (*DeviceTransferSource, error)

OfferDeviceTransfer opens a source-side session and returns a driver. snapshot is the encoded owned-identity snapshot to transfer (its construction is out of scope here). SessionNumber() is shown to the joining device.

func (*DeviceTransferSource) Await

func (s *DeviceTransferSource) Await() (string, error)

Await blocks for a joining device and runs the handshake, returning the SAS to display. The user compares it with the joining device's SAS and, on a match, calls Confirm.

func (*DeviceTransferSource) Close

func (s *DeviceTransferSource) Close() error

Close aborts an in-progress transfer.

func (*DeviceTransferSource) Confirm

func (s *DeviceTransferSource) Confirm(deviceUIDToKeepActive []byte) error

Confirm sends the snapshot to the joining device (call after the user confirms the SAS matched). deviceUIDToKeepActive is optional (single-device profiles). Closes the relay connection.

func (*DeviceTransferSource) SessionNumber

func (s *DeviceTransferSource) SessionNumber() string

SessionNumber returns the number the joining device must enter.

type DiscussionRead added in v0.3.2

type DiscussionRead struct {
	Timestamp          int64               `json:"tim,omitempty"`
	GroupUID           []byte              `json:"guid,omitempty"`
	GroupOwner         []byte              `json:"go,omitempty"`
	GroupV2Identifier  []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier *OneToOneIdentifier `json:"o2oi,omitempty"`
}

DiscussionRead (dr) is a read-state watermark reflected to your own devices: "I read this discussion up to server-timestamp Timestamp on another of my devices" (reference JsonDiscussionRead.java). Other own devices mark the discussion read up to it. Own-device only.

type Disposition added in v0.3.0

type Disposition int

Disposition is what a handler decided about a message, and controls whether it may leave the server inbox. See receiveAndDispatch for how each is honored (Stage 3 wires Retry/Rejected; until then only Consumed vs NotMine are produced).

const (
	// NotMine: no handler took the message (wrong type, or a required callback was unset). Leave it for
	// another pass/consumer.
	NotMine Disposition = iota
	// Consumed: durably handled — the message may be deleted from the server.
	Consumed
	// Retry: transient failure — keep the message on the server so it is re-delivered next pass
	// (at-least-once; asymmetric only, bounded by an attempt cap).
	Retry
	// Rejected: invalid/permanent — drop it uniformly (no distinguishable error).
	Rejected
)

type EmptyCallMessage

type EmptyCallMessage struct{}

EmptyCallMessage is the payload of the signaling messages that carry only their type: reject, hanged-up, ringing, busy.

type Group

type Group struct {
	Identifier     engine.GroupIdentifier
	Keys           *engine.BlobKeys        // main/version seeds + admin key (admin only)
	AdminPublicKey *engine.PublicKeyOverEC // group administration public key
	Blob           *engine.ServerBlob      // last known blob (nil until fetched)
	OwnNonce       []byte                  // our group invitation nonce
	// contains filtered or unexported fields
}

Group is a locally-held view of a group v2 the session participates in.

func (*Group) Delete

func (g *Group) Delete() error

Delete removes the group from the server (spec §47.6). It requires the group administration private key.

func (*Group) Description

func (g *Group) Description() string

Description returns the group's description (the "description" field of its JsonGroupDetails), or "" if unset. Presented as the IRC channel topic.

func (*Group) DiscardPreparedFor

func (g *Group) DiscardPreparedFor(member *engine.CryptoIdentity)

DiscardPreparedFor drops all prepared copies awaiting a member that declined or left the group (spec §34).

func (*Group) IsConfirmed

func (g *Group) IsConfirmed(identity *engine.CryptoIdentity) bool

IsConfirmed reports whether a member is known to have joined.

func (*Group) Leave

func (g *Group) Leave() error

Leave uploads a leave-proof log item for this group (spec §47.5). It requires our group invitation nonce, known from CreateGroup or FetchGroup.

func (*Group) MarkConfirmed

func (g *Group) MarkConfirmed(identity *engine.CryptoIdentity)

MarkConfirmed records that a member has accepted to join the group.

func (*Group) MemberList

func (g *Group) MemberList() []*engine.GroupMember

MemberList returns the group's members (empty if the blob is unknown).

func (*Group) Members

func (g *Group) Members() []*engine.GroupMember

Members returns the current known group members (nil until the blob is fetched or the group is created).

func (*Group) Name

func (g *Group) Name() string

Name returns the group's human-readable name from its serialized details (Olvid JsonGroupDetails, `{"name":…}`), or "" if unknown. Used to label the group (an IRC channel).

func (*Group) PendingCountFor

func (g *Group) PendingCountFor(member *engine.CryptoIdentity) int

PendingCountFor reports how many prepared messages a member is still awaiting (0 once all have been resent).

type GroupInvitation

type GroupInvitation struct {
	Inviter *engine.CryptoIdentity // who invited us (nil when it arrived by broadcast with no channel identity)
	Group   *Group                 // the downloaded, verified group (blob, keys, own invitation nonce)
	// contains filtered or unexported fields
}

GroupInvitation is a received, verified invitation to join a groups-v2 group. By the time you hold one, ProcessGroupInvitation has already downloaded the group blob and cryptographically verified it (administrators chain + our own membership); what remains is the user-facing decision.

The complete receiver-side join-acceptance flow any client follows:

inv, err := session.ProcessGroupInvitation(msg, inviter) // download + verify (returns *GroupInvitation)
if inv.TrustedInviter() {                                // auto-join when a one-to-one contact invited us
    pings, _ := inv.Accept()
} else {                                                 // otherwise surface it and let the user choose
    pings, _ := inv.Accept()  // or inv.Decline()
}
session.DeliverGroupPings(pings)                          // announce our membership to the other members

Accept registers the group locally (it then appears in Session.Group/Session.Groups) and returns the join pings; Decline drops it. The abstraction is transport-agnostic and independent of any particular front-end.

func (*GroupInvitation) Accept

func (inv *GroupInvitation) Accept() ([]OutgoingGroupPing, error)

Accept joins the group and returns a ping for every other member (reference ProcessInvitationDialogResponse, accept branch, → createJoinedGroupV2 + PingMessage). It first registers and persists the group locally (so it then appears in Session.Group/Session.Groups), then builds one recipient-bound join ping per other member; the caller announces membership by delivering them with Session.DeliverGroupPings, which routes each over the member's channel or the asymmetric broadcast.

func (*GroupInvitation) Decline

func (inv *GroupInvitation) Decline() error

Decline rejects the invitation by uploading a leave-proof log item (reference NotifyMembersOfRejectionOrGroupLeft; the server-side proof is §47.5).

func (*GroupInvitation) Description

func (inv *GroupInvitation) Description() string

Description returns the invited group's description (or "" if unset).

func (*GroupInvitation) Name

func (inv *GroupInvitation) Name() string

Name returns the invited group's display name (or "" if unset).

func (*GroupInvitation) TrustedInviter

func (inv *GroupInvitation) TrustedInviter() bool

TrustedInviter reports whether the invitation came from one of our one-to-one contacts — the basis for auto-accepting a group we were added to by someone we already trust.

type GroupMemberSpec

type GroupMemberSpec struct {
	Identity    *engine.CryptoIdentity
	Permissions []string // engine.GroupPermission* strings; defaults to member perms if empty
	Details     string   // serialized identity details (JSON), may be empty
}

GroupMemberSpec describes a member to include when creating a group.

type GroupPingResult

type GroupPingResult struct {
	Sender   *engine.CryptoIdentity // the member that pinged us (recovered from the signature)
	Response *OutgoingGroupPing     // a pong to send back, or nil (ping was already a response)
}

GroupPingResult is the outcome of processing a received ping.

type GroupSendResult

type GroupSendResult struct {
	SentTo                  []*engine.CryptoIdentity // confirmed members delivered to now
	Pending                 []*engine.CryptoIdentity // members the message was prepared (stored) for
	OriginalServerTimestamp int64                    // server timestamp of the first send (resend "ost")
}

GroupSendResult reports the outcome of SendToGroup.

type GroupStore

type GroupStore interface {
	SaveGroupBlob(groupUID, encoded []byte) error
	LoadGroupBlobs() ([][]byte, error)
	DeleteGroup(groupUID []byte) error
}

GroupStore persists groups. Implemented by the store package. Keys are raw group UIDs; values are encodeGroup() blobs (the store handles at-rest encryption).

type GroupUpdateResult

type GroupUpdateResult struct {
	Group         *Group                 // updated local view (new blob + version seed)
	Notifications []OutgoingGroupMessage // InvitationOrMembersUpdate to remaining members
	Kicks         []OutgoingGroupMessage // Kick to removed members
}

GroupUpdateResult is the outcome of an admin update.

type IncomingGroupMessage

type IncomingGroupMessage struct {
	Msg        *engine.ProtocolMessage
	ViaChannel string // contact device-UID hex if it arrived on an oblivious channel, else ""
}

IncomingGroupMessage is a decrypted Groups-v2 protocol message.

type IntroductionInvitation

type IntroductionInvitation struct {
	InstanceUID [32]byte
	Mediator    *engine.CryptoIdentity // who is introducing us (a one-to-one contact)
	Contact     *engine.CryptoIdentity // whom we are being introduced to
	Details     string                 // the contact's serialized published details
}

IntroductionInvitation is a pending inbound introduction: a mediator we trust proposes we connect with Contact. Pass it to AcceptIntroduction or RejectIntroduction.

type IntroductionStore added in v0.3.0

type IntroductionStore interface {
	SaveIntroduction(instanceUID, encoded []byte) error
	LoadIntroductions() ([][]byte, error)
	DeleteIntroduction(instanceUID []byte) error
}

IntroductionStore persists in-flight introductions, keyed by protocol instance UID; values are introState.encode() blobs (the store handles at-rest encryption). Implemented by the store package.

type KeycloakGroup

type KeycloakGroup struct {
	Identifier engine.GroupIdentifier
	Blob       *KeycloakGroupBlob
	Timestamp  int64 // last applied modification timestamp
}

KeycloakGroup is a locally-tracked Keycloak-managed group.

func (*KeycloakGroup) IsMember

func (g *KeycloakGroup) IsMember(identity []byte) bool

IsMember reports whether an identity is listed in the group's member set.

type KeycloakGroupBlob

type KeycloakGroupBlob struct {
	GroupUID                 []byte                `json:"guid"`
	GroupDetails             json.RawMessage       `json:"details"`
	PhotoLabel               []byte                `json:"photo_label"`
	PhotoKey                 []byte                `json:"photo_key"`
	PushTopic                string                `json:"pt"`
	Members                  []KeycloakGroupMember `json:"gm_perms"`
	SerializedSharedSettings string                `json:"sss"`
	Timestamp                int64                 `json:"timestamp"`
}

KeycloakGroupBlob is the signed group structure (reference KeycloakGroupBlob).

func VerifyKeycloakGroupBlob

func VerifyKeycloakGroupBlob(signedJWT string, key *engine.JSONWebKey) (*KeycloakGroupBlob, error)

VerifyKeycloakGroupBlob verifies a signed group blob (JWT) against the Keycloak signature key and returns the parsed blob (spec §34).

type KeycloakGroupDeletion

type KeycloakGroupDeletion struct {
	GroupUID  []byte `json:"groupUid"`
	Timestamp int64  `json:"timestamp"`
}

KeycloakGroupDeletion is a signed group-deletion instruction (reference KeycloakGroupDeletionData).

type KeycloakGroupKick

type KeycloakGroupKick struct {
	GroupUID  []byte `json:"groupUid"`
	Identity  []byte `json:"identity"`
	Timestamp int64  `json:"timestamp"`
}

KeycloakGroupKick is a signed member-kick instruction (reference KeycloakGroupMemberKickedData).

type KeycloakGroupManager

type KeycloakGroupManager struct {
	ServerURL     string
	OwnedIdentity []byte // to check whether a kick targets us
	Key           *engine.JSONWebKey
	Groups        map[string]*KeycloakGroup // keyed by groupUid hex
}

KeycloakGroupManager tracks the Keycloak groups an owned identity belongs to and applies signed updates from the organisation's Keycloak server (reference IdentityManager.updateKeycloakGroups).

func NewKeycloakGroupManager

func NewKeycloakGroupManager(serverURL string, ownedIdentity []byte, key *engine.JSONWebKey) *KeycloakGroupManager

NewKeycloakGroupManager creates an empty manager bound to a Keycloak server, its signature key and the owned identity.

func (*KeycloakGroupManager) ApplySignedBlob

func (m *KeycloakGroupManager) ApplySignedBlob(signedJWT string) (*KeycloakGroup, error)

ApplySignedBlob verifies a signed group blob and creates or updates the group if the blob is newer than the one we hold. A blob older than or equal to the known one is ignored (returns the existing group and no error).

func (*KeycloakGroupManager) ApplySignedDeletion

func (m *KeycloakGroupManager) ApplySignedDeletion(signedJWT string) (bool, error)

ApplySignedDeletion verifies a signed deletion and removes the group if the instruction is newer than the group we hold. Returns whether a group was deleted.

func (*KeycloakGroupManager) ApplySignedKick

func (m *KeycloakGroupManager) ApplySignedKick(signedJWT string) (bool, error)

ApplySignedKick verifies a signed kick and, if it targets us and is newer than the group we hold, removes the group locally. Returns whether we were kicked.

func (*KeycloakGroupManager) Update

func (m *KeycloakGroupManager) Update(signedBlobs, signedDeletions, signedKicks []string) error

Update applies a batch of signed blobs, deletions and kicks in the reference order (deletions, then kicks, then blobs); staleness is resolved by timestamp.

type KeycloakGroupMember

type KeycloakGroupMember struct {
	KeycloakUserID       string   `json:"id"`
	Identity             []byte   `json:"identity"`
	SignedUserDetails    string   `json:"signature"` // the member's own signed details (opaque here)
	Permissions          []string `json:"permissions"`
	GroupInvitationNonce []byte   `json:"nonce"`
}

KeycloakGroupMember is a member entry inside a Keycloak group blob (reference KeycloakGroupMemberAndPermissions).

type LimitedVisibilityOpened added in v0.3.2

type LimitedVisibilityOpened struct {
	Reference          *MessageReference   `json:"m,omitempty"`
	GroupUID           []byte              `json:"guid,omitempty"`
	GroupOwner         []byte              `json:"go,omitempty"`
	GroupV2Identifier  []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier *OneToOneIdentifier `json:"o2oi,omitempty"`
}

LimitedVisibilityOpened (lvo) signals that a limited-visibility (read-once / timed) message, identified by Reference = (sender, sti, ssn), was opened on another of your devices (reference JsonLimitedVisibilityMessageOpened.java). Other own devices start the same burn timer. Own-device only.

type LocationInfo

type LocationInfo struct {
	Type              int      `json:"t"`
	Timestamp         int64    `json:"ts"`
	Latitude          *float64 `json:"lat,omitempty"`
	Longitude         *float64 `json:"long,omitempty"`
	Altitude          *float64 `json:"alt,omitempty"`
	Precision         *float64 `json:"prec,omitempty"`
	Address           string   `json:"add,omitempty"`
	Count             *int64   `json:"c,omitempty"`
	Quality           *int     `json:"q,omitempty"`
	SharingExpiration *int64   `json:"se,omitempty"`
}

LocationInfo describes a shared/sent location (spec §22.2).

type MessageContent

type MessageContent struct {
	Body                    string              `json:"body,omitempty"`
	SenderSequenceNumber    int64               `json:"ssn,omitempty"`
	SenderThreadIdentifier  string              `json:"sti,omitempty"` // UUID string
	GroupUID                []byte              `json:"guid,omitempty"`
	GroupOwner              []byte              `json:"go,omitempty"`
	GroupV2Identifier       []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier      *OneToOneIdentifier `json:"o2oi,omitempty"`
	Forwarded               *bool               `json:"fw,omitempty"`
	OriginalServerTimestamp *int64              `json:"ost,omitempty"`
	Reply                   *MessageReference   `json:"re,omitempty"`
	Expiration              *MessageExpiration  `json:"exp,omitempty"`
	Location                *LocationInfo       `json:"loc,omitempty"`
	Mentions                []UserMention       `json:"um,omitempty"`
}

MessageContent is the actual message (spec §22.2, "Message content").

type MessageExpiration

type MessageExpiration struct {
	ExistenceDuration  *int64 `json:"ex,omitempty"`  // seconds
	VisibilityDuration *int64 `json:"vis,omitempty"` // seconds
	ReadOnce           *bool  `json:"ro,omitempty"`
}

MessageExpiration carries ephemeral-message settings (spec §22.2, "Message expiration").

type MessagePayload

type MessagePayload struct {
	Message             *MessageContent         `json:"message,omitempty"`
	ReturnReceipt       *ReturnReceipt          `json:"rr,omitempty"`
	WebRTC              *WebRTCMessage          `json:"rtc,omitempty"`
	Settings            *SharedSettings         `json:"settings,omitempty"`
	QuerySharedSettings *QuerySharedSettings    `json:"qss,omitempty"`
	UpdateMessage       *UpdateMessage          `json:"upm,omitempty"`
	DeleteMessages      *DeleteMessages         `json:"delm,omitempty"`
	DeleteDiscussion    *DeleteDiscussion       `json:"deld,omitempty"`
	Reaction            *Reaction               `json:"reacm,omitempty"`
	ScreenCapture       *ScreenCaptureDetection `json:"scd,omitempty"`

	// Own-device-only state signals (multi-device sync; see MESSAGE_SYNC.md). The reference posts
	// these with the owned identity as the sole recipient, so they only ever arrive on an own-device
	// channel.
	DiscussionRead          *DiscussionRead          `json:"dr,omitempty"`
	LimitedVisibilityOpened *LimitedVisibilityOpened `json:"lvo,omitempty"`
}

MessagePayload is the top-level payload object (spec §22.2, "Message payload JSON"). Exactly one of its sub-messages is typically set.

func DecodeApplicationPayload

func DecodeApplicationPayload(plaintext []byte) (*MessagePayload, error)

DecodeApplicationPayload reverses EncodeApplicationPayload, returning the typed payload from an application-message plaintext.

func NewTextMessage

func NewTextMessage(body string) *MessagePayload

NewTextMessage builds a plain text-message payload (spec §22.2). Callers set the sequence number and thread identifier for real discussions.

func ParseMessagePayload

func ParseMessagePayload(b []byte) (*MessagePayload, error)

ParseMessagePayload decodes a message-payload JSON (spec §22.2).

func (*MessagePayload) Marshal

func (p *MessagePayload) Marshal() ([]byte, error)

Marshal serializes the payload to its JSON wire form (spec §22.2).

type MessageReference

type MessageReference struct {
	SenderSequenceNumber   int64  `json:"ssn"`
	SenderThreadIdentifier string `json:"sti,omitempty"` // UUID string
	SenderIdentifier       []byte `json:"si,omitempty"`
}

MessageReference references a message for replies/updates/deletes (spec §22.2, "Message reference").

type MutedMessage

type MutedMessage struct {
	Muted bool `json:"muted"`
}

MutedMessage is the single in-call data-channel message (spec §38, Table 5). It is exchanged over the WebRTC data channel, not the server; it is modeled here for completeness.

type OneToOneIdentifier

type OneToOneIdentifier struct {
	IdentityA []byte
	IdentityB []byte
}

OneToOneIdentifier identifies a one-to-one discussion (spec §22.2). It is serialized as a two-element JSON array [identityA, identityB] (each base64).

func (OneToOneIdentifier) MarshalJSON

func (o OneToOneIdentifier) MarshalJSON() ([]byte, error)

func (*OneToOneIdentifier) UnmarshalJSON

func (o *OneToOneIdentifier) UnmarshalJSON(b []byte) error

type Option

type Option func(*Session)

Option configures a Session at construction (functional-options pattern).

func WithContactStore

func WithContactStore(cs ContactStore) Option

WithContactStore persists contacts on every mutation (see AddContact/Restore).

func WithContext

func WithContext(ctx context.Context) Option

WithContext binds all of the session's network I/O to ctx (see NewWithContext).

func WithDeviceName added in v0.3.3

func WithDeviceName(name string) Option

WithDeviceName sets this device's name, which Register encrypts (to our own key, so only our own devices can read it) into the push registration — the label shown for this device in the profile's device list on your other devices. Default empty (no name). Ignored if the push registration already carries an encrypted device name.

func WithDisplayName

func WithDisplayName(name string) Option

WithDisplayName sets the display name placed in trust-establishment messages (the label a contact sees for us when adding us). Default empty.

func WithGroupStore

func WithGroupStore(gs GroupStore) Option

WithGroupStore persists groups on every mutation (see AddGroup/Restore).

func WithIntroductionStore added in v0.3.0

func WithIntroductionStore(is IntroductionStore) Option

WithIntroductionStore persists in-flight introductions so they survive a restart (see introduction.go: restoreIntroductions / ReplayPendingIntroductions).

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the structured logger the session emits events to. Without it the session is silent (events are discarded).

func WithPushRegistration

func WithPushRegistration(reg server.PushRegistration) Option

WithPushRegistration sets the push-notification registration used by Register. The default is a WebSocket-only Linux registration with Reactivate=true.

func WithServerCertObserver added in v0.2.4

func WithServerCertObserver(obs server.CertObserver) Option

WithServerCertObserver installs a TLS certificate observer (server.WithCertObserver) on the session's server client, so every connection to an Olvid server (REST API + notification/transfer sockets) is monitored for certificate changes / MITM. Apply before WithContext.

func WithServerClient

func WithServerClient(c *server.Client) Option

WithServerClient replaces the underlying server.Client (e.g. one built with server options such as a custom timeout or HTTP client).

func WithServerUserAgent

func WithServerUserAgent(ua string) Option

WithServerUserAgent sets the User-Agent sent on every request to the Olvid servers and S3, so the client blends in with an official app (see server.UserAgentAndroid / server.UserAgentIOS). Empty keeps the default (Android). Apply before WithContext.

type OutgoingAttachment

type OutgoingAttachment struct {
	Content  []byte
	MIMEType string
	FileName string
}

OutgoingAttachment is a plaintext attachment to send.

type OutgoingGroupMessage

type OutgoingGroupMessage struct {
	Recipient *engine.CryptoIdentity
	Message   *engine.ProtocolMessage
}

OutgoingGroupMessage is a Groups-v2 protocol message the caller must deliver.

type OutgoingGroupPing

type OutgoingGroupPing struct {
	Recipient *engine.CryptoIdentity
	Message   *engine.ProtocolMessage
}

OutgoingGroupPing is a ping the caller must deliver to Recipient.

type OwnDeviceMarker

type OwnDeviceMarker interface {
	MarkOwnDeviceChannel(deviceUID []byte) error
}

OwnDeviceMarker is an optional ChannelStore capability: persisting which channels are to the owned identity's own devices. The store package implements it.

type ProtocolHandler added in v0.3.0

type ProtocolHandler interface {
	ProtocolID() int
	// Reception declares the channel a given message id must have arrived on. Per-message because
	// gating varies within a protocol (e.g. an introduction's invite vs its acceptance).
	Reception(messageID int) ReceptionReq
	// Handle processes an already-gated message and returns its disposition.
	Handle(pm *engine.ProtocolMessage, rc ReceptionContext) Disposition
}

ProtocolHandler processes one protocol's inbound messages. Implemented by client built-ins and, later, registered by the gateway. The interface lives in the client package so the gateway can implement it without an upward import.

type QuerySharedSettings

type QuerySharedSettings struct {
	GroupUID             []byte              `json:"guid,omitempty"`
	GroupOwner           []byte              `json:"go,omitempty"`
	GroupV2Identifier    []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier   *OneToOneIdentifier `json:"o2oi,omitempty"`
	KnownSettingsVersion *int                `json:"ksv,omitempty"`
	Expiration           *MessageExpiration  `json:"exp,omitempty"`
}

QuerySharedSettings queries another user for a discussion's shared settings (spec §22.2, "Query shared settings").

type Reaction

type Reaction struct {
	Reaction                string              `json:"reac"`
	GroupUID                []byte              `json:"guid,omitempty"`
	GroupOwner              []byte              `json:"go,omitempty"`
	GroupV2Identifier       []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier      *OneToOneIdentifier `json:"o2oi,omitempty"`
	Reference               *MessageReference   `json:"ref,omitempty"`
	OriginalServerTimestamp *int64              `json:"ost,omitempty"`
}

Reaction adds/removes a reaction to a message (spec §22.2, "Reaction"). An empty Reaction string removes a previous reaction.

type ReceiptInfo

type ReceiptInfo struct {
	ReaderIdentity []byte // identity of the recipient that acknowledged
	Status         int64  // engine.ReturnReceiptStatusDelivered / ...Read
}

ReceiptInfo is a decoded incoming return receipt: who acknowledged one of our messages and whether it was delivered or read.

type ReceivedAttachment

type ReceivedAttachment struct {
	Metadata *engine.AttachmentMetadata
	Content  []byte
}

ReceivedAttachment pairs an attachment's metadata with the decrypted content.

type ReceivedMessage

type ReceivedMessage struct {
	ServerUID  []byte
	Timestamp  int64
	Payload    []byte   // decrypted, unpadded encoded payload (encodeList(messageType, elements))
	ViaChannel string   // hex device UID the message arrived on (empty if not via an oblivious channel)
	Sender     *Contact // resolved sender contact, if the channel is attributed (nil otherwise)
}

ReceivedMessage is a downloaded, decrypted application message.

type ReceivedMessageWithAttachments

type ReceivedMessageWithAttachments struct {
	ServerUID         []byte
	Timestamp         int64
	Plaintext         []byte // the full decrypted envelope (encodeList(msgType, elements))
	PayloadJSON       []byte
	Descriptors       [][]byte                         // raw attachment descriptors (payload side)
	ServerAttachments []*server.AttachmentDownloadInfo // download URLs etc. (listing side)
	Header            []byte                           // per-device wrapped key (to derive the extended-payload key)
	HasExtended       bool                             // an extended payload is available (spec §45.1)
	ViaChannel        string                           // hex device UID the message arrived on (empty if not via an oblivious channel)
	Sender            *Contact                         // resolved sender, if the channel's device is attributed to a contact (nil otherwise)
	FromOwnDevice     bool                             // arrived on a channel to one of OUR own devices — a reflection of a message we authored (multi-device sync; see MESSAGE_SYNC.md)
}

ReceivedMessageWithAttachments is a decrypted application message together with its attachment descriptors and the server-side download info.

type ReceptionContext added in v0.3.0

type ReceptionContext struct {
	Sender     *Contact // the contact bound to the oblivious channel that decrypted, or nil (asymmetric/unbound)
	OwnDevice  bool     // the channel is bound to one of our own devices
	ViaChannel string   // device-UID hex of the channel that decrypted ("" for asymmetric)
	UID        []byte   // server message UID (for logging / attempt accounting)
	// contains filtered or unexported fields
}

ReceptionContext describes what decrypting a message established about the channel that carried it. The unexported fields carry per-pass state that built-in (client) handlers need; externally registered (gateway) handlers see only the exported ones.

type ReceptionReq added in v0.3.0

type ReceptionReq int

ReceptionReq is the channel a protocol message must have arrived on to be honored — the "who is allowed to tell me this" boundary, matching the reference `ReceptionChannelInfo`.

const (
	// RecvAny accepts any successful decrypt (asymmetric or oblivious). Used while a handler still
	// performs its own gating internally.
	RecvAny ReceptionReq = iota
	// RecvAsymmetric requires an asymmetric (broadcast) message — no oblivious channel bound it.
	RecvAsymmetric
	// RecvFromContact requires an oblivious channel bound to a contact (not one of our own devices).
	RecvFromContact
	// RecvFromOwnDevice requires an oblivious channel bound to one of our own devices.
	RecvFromOwnDevice
	// RecvFromOneToOneContact requires RecvFromContact AND that the contact is one-to-one.
	RecvFromOneToOneContact
)

type ReconnectCallMessage

type ReconnectCallMessage struct {
	SessionDescriptionType string `json:"sdt"`
	GzippedSDP             []byte `json:"sd"`
}

ReconnectCallMessage re-negotiates an in-progress call (mt=CallReconnect).

type RestoreStore

type RestoreStore interface {
	SessionStore
	SaveOwnedIdentity(owned *engine.OwnedCryptoIdentity, deviceUID []byte) error
}

RestoreStore is a SessionStore that can also persist a freshly restored owned identity — what a co-device restore needs (it writes a new identity into an empty store). The store package satisfies it.

type RestoredBackup

type RestoredBackup struct {
	Format   engine.BackupFormat
	Interop  *engine.BackupJSON // set for BackupFormatOlvidInterop
	Snapshot *engine.Snapshot   // set for BackupFormatLibrary
}

RestoredBackup is the decoded result of a restore, in exactly one of its two shapes.

type ReturnReceipt

type ReturnReceipt struct {
	Nonce []byte `json:"nonce,omitempty"`
	Key   []byte `json:"key,omitempty"`
}

ReturnReceipt carries the nonce and key used to acknowledge delivery/read (spec §22.2, "Return receipt").

type ScreenCaptureDetection

type ScreenCaptureDetection struct {
	GroupUID           []byte              `json:"guid,omitempty"`
	GroupOwner         []byte              `json:"go,omitempty"`
	GroupV2Identifier  []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier *OneToOneIdentifier `json:"o2oi,omitempty"`
}

ScreenCaptureDetection notifies a discussion that the sender captured a sensitive (ephemeral / read-once / limited-visibility) message in it — a screenshot or screen recording (reference JsonScreenCaptureDetection, payload key "scd"). It carries only the discussion identifier; there is no body. The receiver surfaces it as an alert ("X captured a sensitive message").

type Session

type Session struct {
	Owned     *engine.OwnedCryptoIdentity
	DeviceUID []byte
	Server    *server.Client
	Rnd       prng.PRNG

	// ChannelStore, when set, persists an oblivious channel's ratchet state after
	// every mutation (send/receive), so a forward-secret conversation survives a
	// restart. Optional; nil means in-memory only.
	ChannelStore ChannelStore

	// EnableFullRatchet gates the automatic Full Ratchet (spec §33) send-seed
	// refresh. Off by default (rollout safety); when on, a channel refreshes its
	// send direction after 500 messages / 30 days and answers peer-initiated
	// ratchets. See fullratchet.go.
	EnableFullRatchet bool
	// Now overrides the wall clock (ms since epoch) used for full-ratchet timing;
	// nil uses time.Now. For tests.
	Now func() int64
	// contains filtered or unexported fields
}

Session is an authenticated client for one owned identity + device.

A Session is safe for concurrent use: its channel table and authentication token are guarded by an internal RWMutex, so a receive loop, message sends and protocol pumps may run from different goroutines. Operations on a single oblivious channel (repeated sends to the same contact device) should still be serialized by the caller, as they advance that channel's ratchet.

func New

func New(owned *engine.OwnedCryptoIdentity, deviceUID []byte, rnd prng.PRNG, opts ...Option) *Session

New creates a session (the server is derived from the identity's server URL) and applies any options. By default the session is silent and uses a WebSocket-only Linux push registration.

func NewWithContext

func NewWithContext(owned *engine.OwnedCryptoIdentity, deviceUID []byte, rnd prng.PRNG, ctx context.Context) *Session

NewWithContext is New with WithContext(ctx) — a convenience for the common case of binding a session's network I/O to a cancellation context.

func Open

func Open(st SessionStore, rnd prng.PRNG, opts ...Option) (*Session, error)

Open loads an owned identity from a persistent store and returns a fully-restored session: contacts, groups and channels (own-device flags included) are brought back into memory, and all three stores are wired for continued persistence. This replaces the hand-rolled load-identity → New → LoadChannels → AddChannel → Restore boilerplate.

func RestoreFromSnapshot

func RestoreFromSnapshot(st RestoreStore, snapshot []byte, rnd prng.PRNG, opts ...Option) (*Session, error)

RestoreFromSnapshot builds a new co-device session from a device-transfer snapshot (the bytes engine.DeviceTransferParty.ReceiveSnapshot returns): it reconstructs the owned identity, mints a fresh random device UID, persists the identity plus the snapshot's contacts and groups into the store, and returns a ready session.

The store now holds the profile's REAL long-term private keys — protect it (encrypted at rest, 0600; see MULTIDEVICE.md §7). After this, call Register() to announce the new device, then ResyncAfterRestore() to re-fetch each contact's devices and each group's blob (details/members are not in the snapshot). Own-device channels with the other device(s) are established separately (owned-device discovery + channel creation).

func (*Session) AcceptIntroduction

func (s *Session) AcceptIntroduction(inv *IntroductionInvitation) error

AcceptIntroduction accepts a pending introduction: it signs [mediator, other, self] and sends the other party our device UIDs + signature over an asymmetric channel (no oblivious channel to them exists yet). If the other already notified us, that notification is processed now.

func (*Session) AddChannel

func (s *Session) AddChannel(contactDeviceUID []byte, ch *engine.ObliviousChannel)

AddChannel registers an established oblivious channel to a contact device (identity unbound). Prefer AddContactChannel, which binds the peer identity for sender attribution.

func (*Session) AddContact

func (s *Session) AddContact(c *Contact) error

AddContact registers (or replaces) a contact and persists it if a ContactStore is set.

func (*Session) AddContactChannel

func (s *Session) AddContactChannel(contact *Contact, deviceUID []byte, ch *engine.ObliviousChannel) error

AddContactChannel registers an oblivious channel to a contact device, binding the peer identity (for sound sender attribution) and adding the device to the contact. This is the recommended way to register a contact channel; plain AddChannel leaves it unbound.

func (s *Session) AddContactViaLink(link string) (*TrustEstablishment, *engine.ObvURLIdentity, error)

AddContactViaLink begins onboarding a contact from their invitation link: it parses the link, discovers the peer's device(s), and starts a SAS Trust Establishment as initiator. It returns the TrustEstablishment to drive (Pump/SAS/CheckSAS) and the parsed identity. The peer must accept the request on their device; the 4-digit SAS is compared out of band.

func (*Session) AddGroup

func (s *Session) AddGroup(g *Group) error

AddGroup registers (or replaces) a group and persists it if a GroupStore is set.

func (*Session) AddGroupMember

func (s *Session) AddGroupMember(g *Group, contact *Contact) (*GroupUpdateResult, error)

AddGroupMember adds a contact to a group (admin action): it updates the blob to the current membership plus the contact. Deliver the returned notifications with DeliverGroupOutgoing.

func (*Session) AddOwnDeviceChannel

func (s *Session) AddOwnDeviceChannel(ownDeviceUID []byte, ch *engine.ObliviousChannel)

AddOwnDeviceChannel registers an oblivious channel to one of this identity's *own* other devices and marks it as such, so sync atoms received on it are honored and BroadcastSyncAtom fans out to it. Use this instead of AddChannel for own-device channels.

func (*Session) AnnounceCapabilities added in v0.3.0

func (s *Session) AnnounceCapabilities(peer *engine.CryptoIdentity, deviceUID []byte, ownDevice, isResponse bool) error

AnnounceCapabilities sends this device's capabilities to one peer device — a contact device (ownDevice=false) or one of our own other devices (ownDevice=true). isResponse must be true only when replying to a peer's announcement, so the handshake does not loop. Best-effort (fire over the channel).

func (*Session) AnnounceCapabilitiesToAllChannels added in v0.3.0

func (s *Session) AnnounceCapabilitiesToAllChannels()

AnnounceCapabilitiesToAllChannels announces this device's capabilities to every established channel — contact devices and our own other devices. Best-effort; used at startup so peers (re)learn our set after a restart (which reloads channels but re-exchanges nothing).

func (*Session) ApplyInteropBackup

func (s *Session) ApplyInteropBackup(b *engine.BackupJSON) error

ApplyInteropBackup reconstitutes the contacts and groups from a decrypted interop backup into this session, which must already hold the backup's owned identity. Groups are restored minimally (identifier + blob keys + own nonce); their authoritative blob is re-fetched by ResyncAfterRestore. Contacts and groups are persisted if stores are set.

func (*Session) Authenticate

func (s *Session) Authenticate() error

Authenticate obtains (or refreshes) the session token.

func (*Session) BeginChannelCreation

func (s *Session) BeginChannelCreation(contact *engine.CryptoIdentity, contactDeviceUID []byte, instanceUID [32]byte) (*ChannelCreation, error)

BeginChannelCreation starts creating an oblivious channel to a contact device and sends the initial ping (spec §26). contactDeviceUID identifies the peer device; instanceUID must match on both sides.

func (*Session) BeginOwnedDeviceChannelCreation

func (s *Session) BeginOwnedDeviceChannelCreation(otherDeviceUID []byte, instanceUID [32]byte) (*ChannelCreation, error)

BeginOwnedDeviceChannelCreation starts creating an oblivious channel to one of this identity's OWN other devices (spec §26, protocol 22) and sends the initial ping. Drive it with Pump; on completion the channel is registered as an own-device channel (so sync messages are honored). Both devices run this with the SAME instanceUID.

func (*Session) BeginTrustEstablishment

func (s *Session) BeginTrustEstablishment(contact *engine.CryptoIdentity, contactDeviceUID []byte, instanceUID [32]byte, initiator bool) (*TrustEstablishment, error)

BeginTrustEstablishment starts (or joins) a SAS exchange with a contact. The commitment is sent to contactDeviceUID; instanceUID must match on both sides. This session's device UID and display name (WithDisplayName) are placed in the outgoing messages so the peer can address us back and label the contact.

func (*Session) BroadcastSyncAtom

func (s *Session) BroadcastSyncAtom(atom *engine.SyncAtom) (sent int, err error)

BroadcastSyncAtom encodes atom and posts it to every registered own-device channel (ref SendSingleItemSyncMessageStep, which posts to all owned confirmed channels). Delivery is best-effort: a device offline now reconciles later via a full snapshot. It returns the number of devices reached and the first send error, if any.

func (*Session) CancelTrust added in v0.3.0

func (s *Session) CancelTrust(instance [32]byte) bool

CancelTrust aborts an in-flight exchange. Returns whether one was found.

func (*Session) Channel

func (s *Session) Channel(contactDeviceUID []byte) *engine.ObliviousChannel

Channel returns the oblivious channel to a contact device, or nil.

func (*Session) ChannelDeviceForContact

func (s *Session) ChannelDeviceForContact(identity []byte) []byte

ChannelDeviceForContact returns a device UID of the identity we hold a (non-own) oblivious channel to, or nil if none — the device to address a forward-secret send or a group invitation to.

func (*Session) Contact

func (s *Session) Contact(identity *engine.CryptoIdentity) *Contact

Contact returns the contact for an identity, or nil.

func (*Session) ContactBackupInputs

func (s *Session) ContactBackupInputs() []ContactBackupInput

ContactBackupInputs builds interop-backup contact inputs from the session's contacts — a bridge from the live contact set to CreateBackup's Contacts option.

func (*Session) ContactByBytes

func (s *Session) ContactByBytes(identity []byte) *Contact

ContactByBytes returns the contact for raw identity bytes, or nil.

func (*Session) ContactByDeviceUID

func (s *Session) ContactByDeviceUID(deviceUID []byte) *Contact

ContactByDeviceUID returns the contact bound to a device UID's channel (the channel's peer identity), or nil. Attribution follows the cryptographic channel binding, not an attacker-assertible device→identity map.

func (*Session) ContactCapabilities added in v0.3.0

func (s *Session) ContactCapabilities(identity []byte) []string

ContactCapabilities returns the contact's effective capability set — the intersection across every device of the contact we have heard capabilities from. An unknown device does not constrain the result; a device that reported no capabilities forces it empty (reference semantics). Empty if we have heard nothing yet.

func (*Session) ContactSnapshot

func (s *Session) ContactSnapshot(identity []byte) *Contact

ContactSnapshot returns a deep copy of a contact, taken under the session lock, or nil if the identity is not a contact. Callers on other goroutines (e.g. the gateway's IRC-read goroutine) must use this rather than the live *Contact from ContactByBytes: the receive/pump goroutine mutates the live contact's fields (DisplayName, OneToOne, DeviceUIDs, …) in place, so reading them off a shared pointer without the lock is a data race.

func (*Session) Contacts

func (s *Session) Contacts() []*Contact

Contacts returns a snapshot of the session's contacts.

func (*Session) CreateBackup

func (s *Session) CreateBackup(seed engine.BackupSeed, format engine.BackupFormat, opts BackupOptions) ([]byte, error)

CreateBackup builds an encrypted backup of this session's owned identity in the chosen format, under seed. Returns the backup blob (ciphertext ∥ MAC) to store or export.

func (*Session) CreateGroup

func (s *Session) CreateGroup(others []GroupMemberSpec, groupDetails, groupType string) (*Group, error)

CreateGroup builds and uploads the first version of a group blob (spec §47.1). The owned identity is administrator; any member whose permissions include "ga" also becomes an administrator in the initial chain block. It returns the Group together with the blob keys that must be shared with members.

func (*Session) CreateInteropBackupFromState

func (s *Session) CreateInteropBackupFromState(seed engine.BackupSeed, published, latest engine.IdentityDetailsBackup, apiKey string, timestampMillis int64) ([]byte, error)

CreateInteropBackupFromState builds an Olvid-interop backup populated from the session's live, persisted state: every registered contact and group is included automatically. details/apiKey stamp the owned-identity node; timestampMillis stamps the backup.

func (*Session) CreationInFlight added in v0.2.0

func (s *Session) CreationInFlight(device []byte) bool

CreationInFlight reports whether a channel-creation handshake to the given contact device is currently in progress (exported for status/diagnostics such as the gateway's `contact` command).

func (*Session) DeactivateThisDevice

func (s *Session) DeactivateThisDevice() error

DeactivateThisDevice deactivates this device on its server (device-management, spec §46.4): the server marks the device inactive, drops its push expiration/topic, and thereafter treats it as unregistered. For a single-device profile this removes the identity's last server presence — the equivalent of "delete profile" server-side (there is no central identity to delete; an Olvid identity is a self-generated keypair). Requires auth; does not touch the local store.

func (*Session) DeleteContact added in v0.3.0

func (s *Session) DeleteContact(identity []byte) error

DeleteContact removes a contact end to end: it tells the contact we removed them, tells our own other devices to do the same, then tears down the channels and drops the contact locally. It refuses if the contact still shares a group with us — remove them from the group first (reference fail-if-in-groups). Notifications are best-effort and sent BEFORE the channels are torn down (they need those channels).

func (*Session) DeleteMessages

func (s *Session) DeleteMessages(serverUIDs [][]byte) error

DeleteMessages removes messages from the server inbox by their ServerUID. Use it after processing messages fetched with a non-deleting receive (e.g. ReceiveMessagesWithAttachments, which leaves messages on the server so their attachments can be downloaded first).

func (*Session) DeliverGroupInvitation

func (s *Session) DeliverGroupInvitation(g *Group, member *engine.CryptoIdentity) (viaChannel bool, err error)

DeliverGroupInvitation sends a member the group invitation/members-update carrying the blob keys, picking the transport automatically:

  • if we hold a confirmed oblivious channel to the member, over it (variant id 4);
  • otherwise via an asymmetric broadcast (variant id 5), so a freshly-added member receives the invitation immediately — without waiting for a channel to be established.

This is the reusable entry point any client should use to invite/notify a group member; it returns whether the message went over an oblivious channel (vs a broadcast).

func (*Session) DeliverGroupOutgoing

func (s *Session) DeliverGroupOutgoing(msgs []OutgoingGroupMessage) (sent, pending int, err error)

DeliverGroupOutgoing sends each group protocol message (the invitation/members-update and kick notifications returned by CreateGroup/UpdateGroup) over the recipient's oblivious channel. Recipients we hold no channel with are counted as pending (unreachable for now, not an error). Returns (sent, pending).

func (*Session) DeliverGroupPings

func (s *Session) DeliverGroupPings(pings []OutgoingGroupPing) (sent int, err error)

DeliverGroupPings sends each join/response ping over the ASYMMETRIC broadcast channel to every one of the recipient's devices. This transport is mandatory, not an optimization: the reference always posts pings over createAsymmetricBroadcastChannelInfo and its ProcessPingStep only accepts them via createAsymmetricChannelInfo() — a PingMessage arriving over an oblivious channel is never dispatched to the ping step, so it is silently dropped. Sending a pong over an oblivious channel therefore leaves the pinging member unconfirmed forever (their group shows no confirmed co-member and may not surface at all). It returns how many pings were sent.

func (*Session) DeviceCapabilities added in v0.3.0

func (s *Session) DeviceCapabilities(deviceUID []byte) []string

DeviceCapabilities returns the raw capabilities a specific device advertised, or nil if unknown.

func (*Session) DiscoverContactDevices

func (s *Session) DiscoverContactDevices(c *Contact) ([][]byte, error)

DiscoverContactDevices runs device discovery for a contact and updates (and persists) its DeviceUIDs.

func (*Session) DiscoverDevices

func (s *Session) DiscoverDevices(identity *engine.CryptoIdentity) ([][]byte, error)

DiscoverDevices returns the device UIDs of an identity (spec §46.2).

func (*Session) DisplayName

func (s *Session) DisplayName() string

DisplayName returns the display name currently presented to peers.

func (*Session) DowngradeContact added in v0.3.0

func (s *Session) DowngradeContact(identity []byte) error

DowngradeContact flips a contact from one-to-one to non-one-to-one (reference downgrade): set the flag locally, tell the contact, and propagate to our own devices. Channels and the contact record are kept.

func (*Session) DownloadAttachmentTo

func (s *Session) DownloadAttachmentTo(info *server.AttachmentDownloadInfo, key *engine.AuthEncKey, w io.Writer) error

func (*Session) DownloadAttachments

func (s *Session) DownloadAttachments(descriptors [][]byte, serverInfos []*server.AttachmentDownloadInfo) ([]ReceivedAttachment, error)

DownloadAttachments decrypts a received message's attachments: for each descriptor in the decoded payload it downloads the chunks from the matching server descriptor and decrypts them (spec §45.1, §23.3). descriptors are the raw descriptors from DecodeApplicationMessageAttachments; serverInfos are the parsed AttachmentDownloadInfo from the message listing, matched by position.

func (*Session) DownloadExtendedPayload

func (s *Session) DownloadExtendedPayload(messageUID, header []byte) ([]byte, error)

DownloadExtendedPayload fetches and decrypts a message's extended payload (spec §23.2, §45.2). header is the message's per-device wrapped key (from ReceivedMessageWithAttachments.Header), used to derive the extended-payload key. Returns the decrypted extended payload (opaque bytes — e.g. the thumbnail mosaic JPEG, whose rendering is left to the application).

func (*Session) EnsureOwnedDeviceChannels added in v0.3.2

func (s *Session) EnsureOwnedDeviceChannels() error

EnsureOwnedDeviceChannels lists this identity's own devices (spec §46.3) and starts an own-device channel-creation handshake to each one other than this device (skipping any it already has a channel or in-flight handshake to — so it is idempotent and safe to call from a periodic sweep). The receive dispatcher drives each to completion. This is what brings up the oblivious channels the profile's devices share, over which multi-device sync flows — the reference does the same (owned-device discovery + channel creation) after a transfer restore. Because the joining `-join` process exits before the pump can complete these handshakes, the running gateway must call this on startup (and periodically) to actually establish them.

func (*Session) FetchGroup

func (s *Session) FetchGroup(gid engine.GroupIdentifier, keys *engine.BlobKeys) (*Group, error)

FetchGroup downloads, decrypts and verifies a group blob (spec §47.2). The caller must already hold the blob keys (obtained on group creation or through an invitation). Leave-log items returned by the server are consolidated into the returned blob.

func (*Session) GetTurnCredentials

func (s *Session) GetTurnCredentials(username1, username2 string) (*server.TurnCredentials, error)

GetTurnCredentials retrieves TURN credentials to initiate a call (spec §49.2): two username/password pairs (one for the caller, one to hand the recipient in the start-call message). username1/username2 are caller-chosen usernames the server timestamps and signs. Requires the call permission on the licence.

func (*Session) Group

func (s *Session) Group(gid engine.GroupIdentifier) *Group

Group returns the group for an identifier, or nil.

func (*Session) GroupByGID2

func (s *Session) GroupByGID2(gid2 []byte) *Group

GroupByGID2 finds a known group by the group-v2 identifier bytes carried in a message payload (`gid2` == GroupIdentifier.Encode()). Returns nil if the group is unknown.

func (*Session) Groups

func (s *Session) Groups() []*Group

Groups returns a snapshot of the session's groups.

func (*Session) HasChannel

func (s *Session) HasChannel(contactDeviceUID []byte) bool

HasChannel reports whether an oblivious channel to the contact device exists.

func (*Session) HasChannelToContact

func (s *Session) HasChannelToContact(c *Contact) bool

HasChannelToContact reports whether at least one (non-own-device) oblivious channel to the contact is registered — i.e. whether forward-secret application messages can be sent to them yet.

func (*Session) IntroduceContacts

func (s *Session) IntroduceContacts(a, b *Contact) error

IntroduceContacts, as mediator, introduces two of our one-to-one contacts to each other. It sends each a MediatorInvitation naming the other (over the oblivious channel), under one shared protocol instance. Both must be reachable over a confirmed oblivious channel.

func (s *Session) InvitationLink(displayName string) string

InvitationLink returns this session's own sharing invitation link, to hand to a contact.

func (*Session) InviteAllMembers

func (s *Session) InviteAllMembers(g *Group) (sent, pending int, err error)

InviteAllMembers sends a fresh group invitation to every non-self member over its channel (used right after CreateGroup so members can download the blob and join). Returns (sent, pending).

func (*Session) InviteToGroup

func (s *Session) InviteToGroup(g *Group, member *engine.CryptoIdentity, memberDeviceUID []byte) error

InviteToGroup sends a group invitation to a member over their existing oblivious channel (reference InvitationOrMembersUpdateMessage, id 4). Prefer DeliverGroupInvitation, which also handles the no-channel case via a broadcast.

func (*Session) MaintainChannelCreations added in v0.2.0

func (s *Session) MaintainChannelCreations() (retried, gaveUp [][]byte)

MaintainChannelCreations advances every in-flight handshake's idle counter and re-pings (with a fresh instance) any self-initiated one that has stalled — no progress for ccRetryIdleTicks — up to ccMaxAttempts pings; past that (or for an adopted/peer-initiated handshake) it gives up and returns the device so the caller can notify. Call once per pump tick. It self-heals a device whose handshake stalled (previously only a restart's sweep would retry). Pump-goroutine only; may do network I/O.

func (*Session) NotifyContactToRediscoverDevices added in v0.3.2

func (s *Session) NotifyContactToRediscoverDevices(identity []byte)

NotifyContactToRediscoverDevices sends one contact the "re-discover my devices" nudge (reference PerformContactDeviceDiscovery, id 6). Used when a new channel to that contact comes up — e.g. after a -join — so the contact re-discovers our device set and starts addressing this new device too.

func (*Session) NotifyContactsOfDeletion added in v0.3.0

func (s *Session) NotifyContactsOfDeletion()

NotifyContactsOfDeletion tells every contact we are deleting our identity, so they drop us. Each notification is signed and bound to that recipient (so it can't be replayed to another). It is sent over the ASYMMETRIC channel (reference createAsymmetricBroadcastChannelInfo) — NOT the oblivious channel: a real Olvid client only accepts this notification asymmetric-or-own-device, so an oblivious send would be silently dropped by real contacts (audit F1). Best-effort; the caller then performs the irreversible local teardown (DeactivateThisDevice + store wipe).

func (*Session) NotifyContactsToRediscoverDevices added in v0.3.0

func (s *Session) NotifyContactsToRediscoverDevices()

NotifyContactsToRediscoverDevices sends every contact the "re-discover my devices" nudge (reference PerformContactDeviceDiscovery, id 6), used after we change our own device set (e.g. deactivate a device) so contacts stop addressing the removed device.

func (*Session) OnApplicationMessage

func (s *Session) OnApplicationMessage(fn func(*ReceivedMessageWithAttachments))

OnApplicationMessage registers the handler invoked for each decrypted application message during Receive. Nil clears it.

func (*Session) OnCallMessage

func (s *Session) OnCallMessage(fn func(*CallMessage))

OnCallMessage registers the handler for inbound call-signaling messages (spec §38) during Receive. Nil clears it. A call message is an application message whose payload carries a WebRTC "rtc" field; when a call handler is registered such messages route here instead of to OnApplicationMessage.

func (*Session) OnChannelEstablished added in v0.2.0

func (s *Session) OnChannelEstablished(fn func(deviceUID, identity []byte))

OnChannelEstablished registers a callback fired (on the receive goroutine) when a channel-creation handshake confirms an oblivious channel to a contact device.

func (*Session) OnContactDetailsUpdated

func (s *Session) OnContactDetailsUpdated(fn func(*Contact))

OnContactDetailsUpdated registers a handler called when a contact publishes new identity details (the identity-details-publication protocol, e.g. a display-name change): the library has already applied the change to the contact by the time it fires. Nil clears it.

func (*Session) OnContactManagement added in v0.3.0

func (s *Session) OnContactManagement(fn func(ContactMgmtEvent, []byte))

OnContactManagement registers a handler called when an inbound contact-management message (protocol 10) deleted or downgraded a contact — either the contact telling us directly, or one of our own devices propagating it. The library has already applied the change; the callback is for UI (e.g. drop the contact from a roster). Nil clears it.

func (*Session) OnGroupProtocolMessage

func (s *Session) OnGroupProtocolMessage(fn func(pm *engine.ProtocolMessage, viaChannel string))

OnGroupProtocolMessage registers the handler for Groups-v2 protocol messages (invitations, pings, kicks, updates) during Receive. Nil clears it.

func (*Session) OnIntroductionCompleted

func (s *Session) OnIntroductionCompleted(fn func(*Contact))

OnIntroductionCompleted registers a handler called once an introduced contact has been added (their notification verified). Nil clears it.

func (*Session) OnIntroductionInvitation

func (s *Session) OnIntroductionInvitation(fn func(*IntroductionInvitation))

OnIntroductionInvitation registers a handler for an inbound introduction (a mediator proposing a new contact). Nil clears it.

func (*Session) OnOwnedIdentityDeleted added in v0.3.0

func (s *Session) OnOwnedIdentityDeleted(fn func([]byte))

OnOwnedIdentityDeleted registers a handler called when a contact told us (signed) that they deleted their own Olvid identity and we consequently dropped them (protocol 20). The argument is the deleted contact's identity. Nil clears it.

func (*Session) OnProtocolMessage

func (s *Session) OnProtocolMessage(fn func(pm *engine.ProtocolMessage, viaChannel string))

OnProtocolMessage registers the handler for non-Groups-v2 protocol messages (channel creation, SAS, and future protocols such as call signaling) during Receive. Nil clears it.

func (*Session) OnSyncAtom

func (s *Session) OnSyncAtom(fn func(a *engine.SyncAtom, viaChannel string))

OnSyncAtom registers the handler invoked for each sync atom received from one of this identity's own devices during Receive. Nil clears it. Atoms arriving on a channel that is not a registered own-device channel are dropped before reaching this handler.

func (*Session) OnSyncSnapshot

func (s *Session) OnSyncSnapshot(fn func(snap *engine.Snapshot, viaChannel string))

OnSyncSnapshot registers the handler invoked for a full snapshot received from an own device during Receive. Nil clears it. Decode uses the decoders registered via RegisterSnapshotNode; unknown node tags are ignored.

func (*Session) OnTrustEstablished added in v0.3.0

func (s *Session) OnTrustEstablished(fn func(*Contact))

OnTrustEstablished registers a handler called once mutual trust is confirmed and the contact created (the caller typically starts channel creation and updates its roster). Nil clears it.

func (*Session) OnTrustFailed added in v0.3.0

func (s *Session) OnTrustFailed(fn func(TrustInfo, string))

OnTrustFailed registers a handler called when a trust exchange is cancelled (commitment mismatch) or the SAS did not match. The string is a human-readable reason. Nil clears it.

func (*Session) OnTrustInbound added in v0.3.0

func (s *Session) OnTrustInbound(fn func(TrustInfo))

OnTrustInbound registers a handler called when a peer initiates a SAS trust exchange toward us (protocol 11) — for the caller to announce it. Nil clears it. See trust_dispatch.go.

func (*Session) OnTrustSASReady added in v0.3.0

func (s *Session) OnTrustSASReady(fn func(TrustInfo))

OnTrustSASReady registers a handler called when a trust exchange reaches the out-of-band SAS comparison — the info carries the digits to show the peer and the instance to reference in SubmitSAS. Nil clears it.

func (*Session) OnUndecryptable added in v0.1.1

func (s *Session) OnUndecryptable(fn func())

OnUndecryptable registers a handler fired (on the receive goroutine) once per receive pass that had at least one still-retryable message we could not decrypt — typically from a peer device we hold no oblivious channel with. Use it to re-discover devices and start channel creation; keep it cheap or rate-limit, as it can fire on consecutive passes.

func (*Session) OneToOneID

func (s *Session) OneToOneID(c *Contact) *OneToOneIdentifier

OneToOneID returns the one-to-one discussion identifier for a contact: the owned identity and the contact identity in canonical (bytewise-sorted ascending) order, matching the reference so both parties independently compute the same pair. Olvid requires this on 1:1 messages to attribute them to the discussion — a message without it is decrypted but silently dropped.

func (*Session) OwnedDeviceList added in v0.2.5

func (s *Session) OwnedDeviceList() ([]server.OwnedDeviceInfo, *bool, error)

OwnedDeviceList lists this identity's own devices (spec §46.3) with server-side info (expiration, last registration) and whether the account has multi-device enabled (nil if undeterminable). The response is encrypted to our KEM key, so it needs no token.

func (*Session) PollGroupProtocolMessages

func (s *Session) PollGroupProtocolMessages() ([]IncomingGroupMessage, error)

PollGroupProtocolMessages downloads pending messages, decrypts each, and returns the Groups-v2 protocol messages (deleting them from the server). Other messages are left in place for their own runners. It is a thin wrapper over the unified dispatch pass.

func (*Session) ProcessCapabilitiesMessage added in v0.3.0

func (s *Session) ProcessCapabilitiesMessage(pm *engine.ProtocolMessage, viaChannel string) error

ProcessCapabilitiesMessage handles an inbound own-capabilities message (id 3 from a contact, id 4 from an own device). It stores the sender device's advertised set and — on a first-time, non-response announcement — replies once with our own set, completing the handshake. The sender device is taken from the channel it arrived on (viaChannel), and its kind (contact vs own) must match the message variant, so a contact can't masquerade as an own device.

func (*Session) ProcessContactManagementMessage added in v0.3.0

func (s *Session) ProcessContactManagementMessage(pm *engine.ProtocolMessage, viaChannel string) (ContactMgmtEvent, []byte)

ProcessContactManagementMessage applies an inbound contact-management message (id 10), gated on the channel it arrived over: a notification/nudge must come from the contact itself, a propagation from one of our own devices. It returns what happened and the affected contact identity, so the caller can update its UI (e.g. drop the contact from the roster). Runs on the receive goroutine.

func (*Session) ProcessGroupInvitation

func (s *Session) ProcessGroupInvitation(msg *engine.ProtocolMessage, inviter *engine.CryptoIdentity) (*GroupInvitation, error)

ProcessGroupInvitation downloads and verifies the blob an invitation refers to and returns a pending invitation (reference ProcessInvitationOrMembersUpdate + ProcessDownloadedGroupData). inviter is the identity that sent the message, known from the channel it arrived on. It errors unless we are a member and the inviter is a member of the verified group.

func (*Session) ProcessGroupKick

func (s *Session) ProcessGroupKick(msg *engine.ProtocolMessage, g *Group) (kicked bool, kicker *engine.CryptoIdentity, err error)

ProcessGroupKick verifies a kick against the locally known group and reports whether we were validly kicked (reference GetKickedStep). On true the caller should drop the group locally. g must be the member's known group (for the main seed, own nonce and trusted admin-chain prefix).

func (*Session) ProcessGroupLeftBroadcast added in v0.2.5

func (s *Session) ProcessGroupLeftBroadcast(msg *engine.ProtocolMessage) (*Group, error)

ProcessGroupLeftBroadcast handles an invitation-rejected / group-left broadcast (id 16): a member left (or rejected an invitation for) a group we hold. The message carries only the group id, so we re-fetch the blob with the keys we already hold — its leave-log consolidation drops the departed member — applying the same rollback/fork protection as a members update. Returns the refreshed group, or (nil, nil) if we don't hold this group.

func (*Session) ProcessGroupMembersUpdate

func (s *Session) ProcessGroupMembersUpdate(msg *engine.ProtocolMessage) (*Group, error)

ProcessGroupMembersUpdate handles an InvitationOrMembersUpdate for a group we are already in (reference ProcessInvitationOrMembersUpdate, update case): it re-downloads and verifies the blob with the new keys, returning the refreshed group.

func (*Session) ProcessGroupPing

func (s *Session) ProcessGroupPing(msg *engine.ProtocolMessage, g *Group) (*GroupPingResult, error)

ProcessGroupPing verifies a received ping against the known group members and, if it was a request (not a response), returns a pong to send back (reference ProcessPingStep). The sender is identified by matching its invitation nonce and the recipient-bound signature.

func (*Session) ProcessOwnedIdentityDeleted added in v0.3.0

func (s *Session) ProcessOwnedIdentityDeleted(pm *engine.ProtocolMessage) ([]byte, bool)

ProcessOwnedIdentityDeleted handles a contact telling us they deleted their identity (reference ProcessContactOwnedIdentityWasDeletedMessage): verify the signature — which must sign OUR identity under the deleter's authentication key — guard against replay, and drop the contact. Returns the deleted contact's identity and whether we dropped it, so the caller can update its UI.

func (*Session) ProcessPropagatedCommitment added in v0.3.7

func (s *Session) ProcessPropagatedCommitment(pm *engine.ProtocolMessage) (*TrustEstablishment, error)

ProcessPropagatedCommitment builds the Bob-side exchange on one of our OTHER devices from a PropagateCommitmentToBobDevices message (id 4) our answering device broadcast to us: it stores the contact's commitment/details/devices and waits for the propagated accept/reject (id 6). It sends nothing (Bob's other device never answers the contact). See CONTACT_SYNC.md.

func (*Session) ProcessPropagatedInvitation added in v0.3.7

func (s *Session) ProcessPropagatedInvitation(pm *engine.ProtocolMessage) (*TrustEstablishment, string, error)

ProcessPropagatedInvitation builds the Alice-side exchange on one of our OTHER devices from a PropagateInvitationToAliceDevices message (id 2) our initiating device broadcast to us over an own-device channel: it adopts the decommitment + seedAlice and waits for Bob's direct seed/confirmation and our device's propagated entered-SAS. It sends nothing (the initiating device drove the commitment). Returns the exchange and the contact's display name from the message (see CONTACT_SYNC.md).

func (*Session) ProcessReturnReceipt

func (s *Session) ProcessReturnReceipt(nonce, encryptedPayload []byte) (info *ReceiptInfo, ok bool, err error)

ProcessReturnReceipt decrypts an incoming return receipt (from the WebSocket) using the key we minted for its nonce. ok is false when the nonce is unknown (not ours, or evicted) — the caller should ignore it.

func (*Session) ProcessTrustEstablishment

func (s *Session) ProcessTrustEstablishment(pm *engine.ProtocolMessage) (*TrustEstablishment, error)

ProcessTrustEstablishment handles a peer-initiated trust request (the responder-from-inbound path): given the inbound SEND_COMMITMENT protocol message, it builds a responding TrustEstablishment — learning the peer's identity, display name and device UIDs from the message — and sends the seed reply to the peer's device. Drive the returned exchange with Pump → compare SAS() out of band → CheckSAS → Pump until Confirmed → EstablishChannel.

func (*Session) PublishIdentityDetails

func (s *Session) PublishIdentityDetails(details engine.SerializedIdentityDetails, version int) (int, error)

PublishIdentityDetails broadcasts updated owned-identity details to every contact reachable over a confirmed oblivious channel (and to our own other devices), via the identity-details-publication protocol (spec ID 6). This is how a display-name change reaches contacts you already have — trust establishment only carries the name at first contact.

version MUST strictly increase across calls for this identity: the reference receiver rejects a version ≤ the one it already stored, so a caller persists the last-used version and passes the next one. Returns the number of contact devices the update was sent to.

It does not change the name presented in future onboardings — call SetDisplayName for that.

func (*Session) QuerySubscription added in v0.2.5

func (s *Session) QuerySubscription() (server.SubscriptionInfo, error)

QuerySubscription re-authenticates and returns the licence/subscription status the server reports (API-key status, permissions incl. multi-device, and expiration). Refreshes the cached token.

func (*Session) Receive

func (s *Session) Receive() error

Receive performs one reception pass, dispatching to the registered handlers (OnApplicationMessage / OnGroupProtocolMessage / OnProtocolMessage) and deleting the messages they consume. Call it in a loop or on a WebSocket wake-up for a long-running client.

func (*Session) ReceiveMessages

func (s *Session) ReceiveMessages(delete bool) ([]ReceivedMessage, error)

ReceiveMessages downloads pending messages, decrypts each (asymmetric or oblivious channel), and returns the *application* messages. Protocol messages and undecryptable messages are left on the server for a protocol runner. When delete is true, the returned application messages are deleted (spec §45). It is a thin wrapper over the unified dispatch pass.

func (*Session) ReceiveMessagesWithAttachments

func (s *Session) ReceiveMessagesWithAttachments() ([]ReceivedMessageWithAttachments, error)

ReceiveMessagesWithAttachments downloads pending messages, decrypts the application ones, and returns them with parsed attachment descriptors (payload side) and server download info (listing side). It does not delete messages — call Session.DeleteMessages with the returned ServerUIDs once attachments are fetched. It is a thin wrapper over the unified dispatch pass.

func (*Session) ReflectDiscussionRead added in v0.3.2

func (s *Session) ReflectDiscussionRead(dr *DiscussionRead) (sent int, firstErr error)

ReflectDiscussionRead sends a read-state watermark (dr) to your own other devices only — the reference posts it with the owned identity as the sole recipient (Message.java postDiscussionReadMessage). Other own devices mark the discussion read up to dr.Timestamp. Best-effort; no-op with no own-device channel.

func (*Session) ReflectLimitedVisibilityOpened added in v0.3.2

func (s *Session) ReflectLimitedVisibilityOpened(lvo *LimitedVisibilityOpened) (sent int, firstErr error)

ReflectLimitedVisibilityOpened sends an ephemeral-opened signal (lvo) to your own other devices only, so they start the same burn timer for the referenced message (reference postLimitedVisibilityMessageOpenedMessage). Best-effort; no-op with no own-device channel.

func (*Session) ReflectToOwnDevices added in v0.3.2

func (s *Session) ReflectToOwnDevices(appEnvelope []byte) (sent int, firstErr error)

ReflectToOwnDevices sends an already-encoded APPLICATION message envelope (the same bytes sent to the contact/group) to every one of this identity's OTHER devices over their own-device oblivious channels, so a message we authored on this device appears on the others (multi-device reflection — the reference simply adds the owned identity as an extra recipient of the same post; see MESSAGE_SYNC.md). The receiving own device recognizes it as outgoing because it arrives on an own-device channel. Best-effort and a no-op when no own-device channel is up.

func (*Session) Register

func (s *Session) Register() error

Register makes this device reachable and discoverable (spec §46.1) using the session's push registration (WebSocket-only Linux by default; see WithPushRegistration).

func (*Session) RegisterProtocolHandler added in v0.3.0

func (s *Session) RegisterProtocolHandler(h ProtocolHandler)

RegisterProtocolHandler installs a handler for a protocol, replacing any existing one. The gateway uses this to own a protocol's UX-facing processing without a second ProtocolID switch.

func (*Session) RegisterReflectedReturnReceipt added in v0.3.2

func (s *Session) RegisterReflectedReturnReceipt(rr *ReturnReceipt) error

RegisterReflectedReturnReceipt records the nonce→key of a return receipt that arrived on one of our OWN-device channels — a message we authored on another device, reflected back to us (multi-device sync; see MESSAGE_SYNC.md). Registering it lets this device's receipt listener decrypt the single acknowledgement the recipient posts to every sender device, so delivered/read markers converge across all our devices, not just the one that originally sent. No-op when rr is empty or already known.

func (*Session) RegisterSnapshotNode

func (s *Session) RegisterSnapshotNode(tag string, decoder func([]byte) (engine.SnapshotNode, error))

RegisterSnapshotNode registers a decoder for a snapshot node tag, used to decode full snapshots received from own devices. Register one per node type the app understands (e.g. engine.SnapshotTagSettings -> engine.DecodeSettingsNode).

func (*Session) RejectIntroduction

func (s *Session) RejectIntroduction(inv *IntroductionInvitation)

RejectIntroduction drops a pending introduction (no message is sent; the mediator/other simply never hears back).

func (*Session) RemoveChannel added in v0.2.0

func (s *Session) RemoveChannel(contactDeviceUID []byte)

RemoveChannel tears down any oblivious channel to a contact device — from the in-memory registry and, if the store supports it, from disk. It mirrors the reference's deleteObliviousChannelIfItExists (spec §26, SendPingStep): when (re)starting channel creation to a device, any existing one-sided or incompatible channel must be cleared so it cannot shadow the fresh one being negotiated.

func (*Session) RemoveContact

func (s *Session) RemoveContact(identity []byte) error

RemoveContact drops a contact and releases its channels — from memory and (if configured) the store — so a long-running session does not leak per-contact state over churn.

func (*Session) RemoveGroup

func (s *Session) RemoveGroup(gid engine.GroupIdentifier) error

RemoveGroup drops a group from memory and (if configured) the store.

func (*Session) RemoveGroupMember

func (s *Session) RemoveGroupMember(g *Group, identity []byte) (*GroupUpdateResult, error)

RemoveGroupMember removes a member (by identity bytes) from a group (admin action). Deliver the returned notifications and kicks with DeliverGroupOutgoing.

func (*Session) RemoveOwnedDevice added in v0.2.5

func (s *Session) RemoveOwnedDevice(deviceUID []byte) error

RemoveOwnedDevice deactivates one of this identity's OTHER devices on the server (device-management §46.4, request 0x01): the device loses its registration and stops receiving messages. It refuses to remove THIS device — for that use DeactivateThisDevice (oigw -delete), which also cleans up locally. Requires auth. Any own-device channel we held to the removed device is torn down locally; other devices learn of the removal on their next owned-device discovery.

func (*Session) RenameOwnedDevice added in v0.3.0

func (s *Session) RenameOwnedDevice(deviceUID []byte, name string) error

RenameOwnedDevice sets the (encrypted) name of one of this identity's devices (device-management §46.4, request 0x00). The name is encrypted to our own key, so only our devices can read it. An empty name clears it. Requires auth.

func (*Session) ReplayPendingIntroductions added in v0.3.0

func (s *Session) ReplayPendingIntroductions()

ReplayPendingIntroductions re-drives introductions restored from the store. Call it once after installing the introduction handlers (OnIntroductionInvitation / OnIntroductionCompleted): introductions we had not yet accepted re-fire OnIntroductionInvitation so the user is prompted again after a restart; any whose acceptance we had already buffered are completed now.

func (*Session) RequestReturnReceipt

func (s *Session) RequestReturnReceipt() (*ReturnReceipt, error)

RequestReturnReceipt mints the rr to attach to an outbound message so its recipient acknowledges delivery/read, and remembers the key needed to decrypt those acknowledgements (ProcessReturnReceipt). Attach the result to a message payload's ReturnReceipt field.

func (*Session) ResendPreparedTo

func (s *Session) ResendPreparedTo(g *Group, member *engine.CryptoIdentity, contactDeviceUID []byte) (int, error)

ResendPreparedTo resends every prepared message that a now-confirmed member is still awaiting, injecting the original server timestamp ("ost") into each payload (spec §34). It returns the number of messages resent. The member is marked confirmed.

func (*Session) Restore

func (s *Session) Restore() error

Restore loads persisted contacts and groups into the session from its configured stores. It is safe to call once after New(...WithContactStore/WithGroupStore).

func (*Session) RestoreBackup

func (s *Session) RestoreBackup(seed engine.BackupSeed, blob []byte) (*RestoredBackup, error)

RestoreBackup decrypts and parses a backup blob under seed, auto-detecting the payload format. For the library format, decoders registered via RegisterSnapshotNode are used to decode the snapshot nodes.

func (*Session) ResyncAfterRestore

func (s *Session) ResyncAfterRestore() error

ResyncAfterRestore performs the online post-restore re-sync (spec §37): owned-device discovery (so channels come up with the profile's OTHER devices, enabling multi-device sync), device discovery for every contact (so messages can be addressed), and a blob re-fetch for every group with keys (so membership/details are brought up to date, which also auto-creates member contacts). Best-effort: it continues past failures and returns the first error seen.

The owned-device step mirrors the reference OwnedIdentityTransferProtocol, which runs owned-device discovery + channel creation after a transfer restore: it lists the identity's own devices and starts an own-device channel-creation handshake to each one other than this device. The receive dispatcher then drives each handshake to completion and registers the resulting channel as an own-device channel.

func (*Session) RunReturnReceiptListener

func (s *Session) RunReturnReceiptListener(ctx context.Context, onReceipt func(nonce []byte, info *ReceiptInfo))

RunReturnReceiptListener maintains a WebSocket to the identity's server and delivers decoded return receipts (for messages we sent with RequestReturnReceipt) to onReceipt, until ctx is cancelled. Receipts arrive only over the WebSocket (there is no REST poll for them). It reconnects with capped backoff; onReceipt runs on the listener goroutine, so keep it non-blocking. Blocks until ctx done.

func (*Session) SaveGroup

func (s *Session) SaveGroup(g *Group) error

SaveGroup re-persists a group after its state changed (e.g. a new blob version or a newly confirmed member). No-op without a GroupStore.

func (*Session) SendApplicationToContact

func (s *Session) SendApplicationToContact(c *Contact, encodedPayload []byte) (int, error)

func (*Session) SendAttachmentsToContact

func (s *Session) SendAttachmentsToContact(c *Contact, payloadJSON []byte, attachments []OutgoingAttachment) (int, error)

SendAttachmentsToContact sends a message with attachments to a contact over the forward-secret oblivious channel (the transport trusted contacts use — cf. SendApplicationToContact), to each channel-bound device. The envelope (payload + descriptors) is channel-encrypted; the chunks are uploaded to signed URLs. The payload should already carry the message's o2oi/ssn/sti. Returns the number of devices reached. (Chunks are re-PUT per device; contacts usually have one device.)

func (*Session) SendAttachmentsToGroup

func (s *Session) SendAttachmentsToGroup(g *Group, payloadJSON []byte, attachments []OutgoingAttachment) (*GroupSendResult, error)

SendAttachmentsToGroup posts an attachment-bearing message to a group: it delivers to every confirmed member over that member's oblivious channel (mirroring SendToGroup for text and SendAttachmentsToContact for the transfer). The attachments are encrypted once (one key each) but, like every oblivious-channel message, the ciphertext chunks are uploaded per recipient. The payload must already carry the group's gid2 identifier. Members with no confirmed channel are reported as Pending; unlike text, attachments are NOT queued for later resend, so a pending member misses this attachment until it is re-sent after they join.

func (*Session) SendCallMessage

func (s *Session) SendCallMessage(recipient *engine.CryptoIdentity, deviceUIDs [][]byte, callID string, messageType int, smp any) (*server.UploadResult, error)

SendCallMessage sends a call-signaling message to a recipient as an application message (spec §38, §22.2 rtc). smp is the message-specific struct (e.g. StartCallMessage, or EmptyCallMessage for reject/hangup/ringing/busy). callID identifies the call (a UUID string). Returns the upload result.

func (*Session) SendCallMessageToContact

func (s *Session) SendCallMessageToContact(c *Contact, callID string, messageType int, smp any) (*server.UploadResult, error)

SendCallMessageToContact sends a call-signaling message to a contact.

func (*Session) SendMessage

func (s *Session) SendMessage(recipient *engine.CryptoIdentity, deviceUIDs [][]byte, encodedPayload []byte) (*server.UploadResult, error)

SendMessage encrypts an already-encoded payload to a recipient identity on the asymmetric channel and uploads it, one header per device (spec §23.1, §44.1). If deviceUIDs is nil the recipient's devices are discovered.

The payload must be an *encoded* value (§22); use EncodeApplicationMessage.

func (*Session) SendMessageToContact

func (s *Session) SendMessageToContact(c *Contact, encodedPayload []byte) (*server.UploadResult, error)

SendMessageToContact sends an encoded payload to a contact, addressing all its known devices. Equivalent to SendMessage(c.Identity, c.DeviceUIDs, payload).

func (*Session) SendMessageWithAttachmentStream

func (s *Session) SendMessageWithAttachmentStream(recipient *engine.CryptoIdentity, deviceUIDs [][]byte, payloadJSON []byte, attachments []StreamingAttachment, extendedPayload []byte) (*server.UploadResult, error)

SendMessageWithAttachmentStream is the streaming counterpart of SendMessageWithAttachments: it encrypts and uploads each attachment one chunk at a time (peak memory ≈ one chunk, AttachmentChunkDataSize), so it scales to large files (spec §22.2, §23.3, §44.1). The attachment sizes are declared to the server up front from the reader's length (computed during the hash pass).

func (*Session) SendMessageWithAttachments

func (s *Session) SendMessageWithAttachments(recipient *engine.CryptoIdentity, deviceUIDs [][]byte, payloadJSON []byte, attachments []OutgoingAttachment) (*server.UploadResult, error)

SendMessageWithAttachments encrypts each attachment, embeds their keys and metadata in the payload, uploads the message to the recipient's devices over the asymmetric channel declaring the attachments, then PUTs every encrypted chunk to its signed URL (spec §22.2, §23.3, §44.1). Returns the upload result.

func (*Session) SendMessageWithAttachmentsExt

func (s *Session) SendMessageWithAttachmentsExt(recipient *engine.CryptoIdentity, deviceUIDs [][]byte, payloadJSON []byte, attachments []OutgoingAttachment, extendedPayload []byte) (*server.UploadResult, error)

SendMessageWithAttachmentsExt is like SendMessageWithAttachments but also carries an optional extended payload (spec §23.2) — e.g. a small preview of image attachments. The bytes are opaque here (building the thumbnail mosaic is an application concern); they are encrypted under a key derived from the message key and uploaded with the message.

func (*Session) SendMessageWithAttachmentsToContact

func (s *Session) SendMessageWithAttachmentsToContact(c *Contact, payloadJSON []byte, attachments []OutgoingAttachment) (*server.UploadResult, error)

SendMessageWithAttachmentsToContact sends a message with attachments to a contact.

func (*Session) SendOnChannel

func (s *Session) SendOnChannel(recipient *engine.CryptoIdentity, contactDeviceUID, encodedPayload []byte) (*server.UploadResult, error)

SendOnChannel sends a payload over the established, forward-secret oblivious channel to a contact device (spec §23.1, oblivious channel). Requires a prior channel (see EstablishChannel).

func (*Session) SendReturnReceipt

func (s *Session) SendReturnReceipt(sender *engine.CryptoIdentity, rr *ReturnReceipt, status int64) error

SendReturnReceipt acknowledges a received message to its sender. sender is the message's sender (the receipt's recipient); rr is the message's ReturnReceipt. The receipt goes to every device of the sender we hold a channel with. It is a no-op when the message requested no receipt (rr nil/empty) or we know no device for the sender.

func (*Session) SendSnapshot

func (s *Session) SendSnapshot(ownDeviceUID []byte, snapshot *engine.Snapshot) error

SendSnapshot sends a full profile snapshot to one own device for reconciliation (ref the SynchronizationProtocol snapshot exchange). The peer compares it against its own snapshot (Snapshot.ContentsEqual / Diff) and updates as needed.

func (*Session) SendToGroup

func (s *Session) SendToGroup(g *Group, payloadJSON []byte, deviceUIDs map[string][]byte) (*GroupSendResult, error)

SendToGroup posts a message-payload JSON to the group (spec §34). It delivers to every confirmed member for which deviceUIDs holds a contact device UID (over that member's oblivious channel), and prepares an unsent copy for every other member. deviceUIDs maps a member identity-hex to its contact device UID.

func (*Session) SendToGroupAuto

func (s *Session) SendToGroupAuto(g *Group, payloadJSON []byte) (*GroupSendResult, error)

SendToGroupAuto posts a message-payload JSON to a group, resolving each co-member's device from the oblivious channels we hold (see SendToGroup). The payload must already carry the group's `gid2` identifier. Members we have no channel with are queued as pending (SendToGroup handles the resend once they confirm).

func (*Session) SetContext added in v0.2.1

func (s *Session) SetContext(ctx context.Context)

SetContext rebinds the session's network request context after construction. A long-lived (warm) session shared across successive IRC connections uses this so that each connection's disconnect (ctx cancel) aborts the pump's in-flight I/O promptly, and the next connection rebinds to its own ctx. Call it while no receive/send goroutine is running on the session (on attach, before the pump starts).

func (*Session) SetDeviceNonExpiring added in v0.2.1

func (s *Session) SetDeviceNonExpiring(deviceUID []byte) error

SetDeviceNonExpiring marks one of this identity's devices as non-expiring (device-management, spec §46.4, request type 0x02). The device transfer's source designates a deviceUidToKeepActive for device-limited profiles; the joining device calls this after Register() so the server keeps that device active (reference OwnedIdentityTransferProtocol SetUnexpiringDevice / iOS requestServerToKeepDeviceActive). Requires auth.

func (*Session) SetDisplayName

func (s *Session) SetDisplayName(name string)

SetDisplayName changes the display name presented to peers in future trust-establishment exchanges (the label a new contact sees when adding us). It does not republish details to existing contacts — this library has no identity-details-publication protocol — so it affects onboardings started after the call. Safe to call concurrently with the receive/pump goroutine.

func (*Session) StartChannelCreation added in v0.2.0

func (s *Session) StartChannelCreation(contact *engine.CryptoIdentity, contactDeviceUID []byte) error

StartChannelCreation begins a Channel Creation to a contact device (spec §26) and registers it so the receive loop drives it to completion. It mints a fresh protocol instance, sends the initial ping, and is a no-op if a creation to this device is already in flight or a channel already exists.

func (*Session) StartOwnedDeviceChannelCreation added in v0.2.1

func (s *Session) StartOwnedDeviceChannelCreation(otherDeviceUID []byte) error

StartOwnedDeviceChannelCreation begins a Channel Creation to one of this identity's OWN other devices (spec §26, protocol 22) and registers it so the receive loop drives it to completion — the own-device analogue of StartChannelCreation. On confirmation the channel is registered as an own-device channel (so multi-device sync atoms/snapshots from it are honored). It mints a fresh protocol instance, sends the initial ping, and is a no-op if a channel or handshake to this device already exists. Used after a device transfer to bring up channels with the profile's other devices (reference OwnedIdentityTransferProtocol runs owned-device discovery + channel creation post-restore).

func (*Session) StartTrust added in v0.3.0

func (s *Session) StartTrust(link string) (TrustInfo, error)

StartTrust begins onboarding a contact from their invitation link (we are the initiator). It sends the commitment and registers the exchange; the SAS prompt then arrives via OnTrustSASReady. It refuses if an exchange with the same peer is already in flight.

func (*Session) StreamAttachments

func (s *Session) StreamAttachments(descriptors [][]byte, serverInfos []*server.AttachmentDownloadInfo, sink func(*engine.AttachmentMetadata) (io.WriteCloser, error)) error

StreamAttachments downloads a received message's attachments one chunk at a time, streaming each decrypted attachment to the writer that sink(metadata) returns (peak memory ≈ one chunk, so it scales to large files — cf. the all-in-memory DownloadAttachments). The writer is closed after each attachment. sink may return a nil writer to skip an attachment.

func (*Session) SubmitSAS added in v0.3.0

func (s *Session) SubmitSAS(instance [32]byte, digits []byte) error

SubmitSAS enters the digits the peer displayed for the exchange with the given instance UID, completing the SAS comparison. On a match it sends our mutual-trust confirmation; if the peer already confirmed, trust completes now (OnTrustEstablished fires). On a mismatch the exchange is aborted (OnTrustFailed fires) and an error is returned.

func (*Session) TrustsAwaitingSAS added in v0.3.0

func (s *Session) TrustsAwaitingSAS() []TrustInfo

TrustsAwaitingSAS returns a snapshot of the exchanges currently waiting for the user to enter the peer's SAS digits.

func (*Session) TrustsInProgress added in v0.3.0

func (s *Session) TrustsInProgress() []TrustInfo

TrustsInProgress returns a snapshot of every in-flight trust exchange.

func (*Session) UpdateGroup

func (s *Session) UpdateGroup(g *Group, newMembers []GroupMemberSpec) (*GroupUpdateResult, error)

UpdateGroup changes a group's membership to exactly the owned identity plus newMembers, keeping the current details and type (reference the admin update flow). Requires the group admin key; the returned notifications/kicks must be delivered by the caller.

func (*Session) UpdateGroupDetails

func (s *Session) UpdateGroupDetails(g *Group, groupDetails string) (*GroupUpdateResult, error)

UpdateGroupDetails changes a group's serialized details (a JsonGroupDetails, e.g. name/description), keeping the current membership and type. Admin-only. Every member is notified and re-downloads the new blob; on their side the new details arrive as "published" details (auto-trusted only for a change made on one of their own devices — otherwise surfaced for the user to accept, per the reference). Build the JSON with SerializeGroupName / SerializeGroupNameAndDescription. The returned notifications must be delivered by the caller.

type SessionStore

type SessionStore interface {
	ContactStore
	GroupStore
	ChannelStore
	IntroductionStore
	OwnDeviceMarker
	LoadOwnedIdentity() (*engine.OwnedCryptoIdentity, []byte, error)
	LoadChannelsInto(add func(deviceUID, encoded []byte, ownDevice bool)) error
}

SessionStore is everything Open needs to restore a full session: the owned identity, the contact/group stores, and channel state (with the own-device flag). The store package satisfies it structurally.

type SharedSettings

type SharedSettings struct {
	Version            int                 `json:"version"`
	GroupUID           []byte              `json:"guid,omitempty"`
	GroupOwner         []byte              `json:"go,omitempty"`
	GroupV2Identifier  []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier *OneToOneIdentifier `json:"o2oi,omitempty"`
	Expiration         *MessageExpiration  `json:"exp,omitempty"`
}

SharedSettings sets a discussion's default ephemeral settings (spec §22.2, "Ephemeral message settings").

type StartCallMessage

type StartCallMessage struct {
	SessionDescriptionType string `json:"sdt"`
	GzippedSDP             []byte `json:"sd"`
	TurnUsername           string `json:"tu"`
	TurnPassword           string `json:"tp"`
}

StartCallMessage initiates a call (mt=CallStart): the offer SDP plus the TURN credentials the recipient uses to join without querying the server (§39.1).

type StatusError

type StatusError struct {
	Op     string        // the operation that failed (for the message)
	Status server.Status // the server status code
}

StatusError wraps a non-OK server status so callers can program against it with errors.As / errors.Is — distinguishing permanent failures (e.g. server.StatusDeviceNotRegistered, StatusPayloadTooLarge) from transient ones — instead of parsing an opaque string. It mirrors the engine's ErrCrypt discipline at the client boundary.

func (*StatusError) Error

func (e *StatusError) Error() string

func (*StatusError) Is

func (e *StatusError) Is(target error) bool

Is matches by status value; a target with empty Op matches any op with the same status, so callers can write errors.Is(err, &StatusError{Status: server.StatusDeviceNotRegistered}).

type StreamingAttachment

type StreamingAttachment struct {
	Reader   io.ReadSeeker
	MIMEType string
	FileName string
}

StreamingAttachment is an outgoing attachment read from an io.ReadSeeker (typically a file), so it never needs to be fully resident in memory. The reader must be seekable: it is read once to hash (for the metadata SHA-256), rewound, then read again to encrypt+upload one chunk at a time.

type TrustEstablishment

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

TrustEstablishment drives one party of the SAS protocol over the network.

func (*TrustEstablishment) Cancelled added in v0.2.5

func (te *TrustEstablishment) Cancelled() bool

Cancelled reports whether the exchange was cancelled by the protocol (e.g. a commitment mismatch).

func (*TrustEstablishment) CheckSAS

func (te *TrustEstablishment) CheckSAS(peerDigits []byte) bool

CheckSAS compares the digits the peer displayed (entered out of band). On a match it sends this party's mutual-trust confirmation; mutual trust completes once the peer's confirmation also arrives (keep Pumping, then check Confirmed()). Returns whether the SAS matched.

func (*TrustEstablishment) Confirmed

func (te *TrustEstablishment) Confirmed() bool

Confirmed reports whether mutual trust has been established (both confirmations exchanged).

func (*TrustEstablishment) EstablishChannel

func (te *TrustEstablishment) EstablishChannel() (*ChannelCreation, error)

EstablishChannel starts Channel Creation (§26) to the peer's PRIMARY device once mutual trust is confirmed, yielding an oblivious channel. Drive the returned ChannelCreation with Pump().

NOTE: this targets te.primaryDevice() ONLY — a single device. A multi-device contact reads on any of their devices, so for messaging you must establish a channel with EVERY device: call DiscoverDevices(§46.2) and BeginChannelCreation per device (this is what the oigw gateway does). Using this method alone against a multi-device peer leaves your messages reaching none of the devices they actually use.

func (*TrustEstablishment) InstanceUID added in v0.2.5

func (te *TrustEstablishment) InstanceUID() [32]byte

InstanceUID returns the exchange's protocol-instance UID (hex-keyable for routing).

func (*TrustEstablishment) PeerDeviceUIDs

func (te *TrustEstablishment) PeerDeviceUIDs() [][]byte

PeerDeviceUIDs returns the peer's device UIDs learned during the exchange.

func (*TrustEstablishment) PeerDisplayName added in v0.2.5

func (te *TrustEstablishment) PeerDisplayName() string

PeerDisplayName returns the peer's display name as learned during the exchange (from the invitation link, else from the commitment's serialized details), or "" if none was provided. Available before the contact is created, so an inbound request can be shown under a real name rather than a placeholder.

func (*TrustEstablishment) PeerIdentity added in v0.2.5

func (te *TrustEstablishment) PeerIdentity() *engine.CryptoIdentity

PeerIdentity returns the peer's crypto identity (known from the invitation link or the inbound commitment), so a caller can label an in-flight exchange before the contact is created.

func (*TrustEstablishment) Pump

func (te *TrustEstablishment) Pump() (awaitingSAS bool, err error)

Pump downloads pending messages, feeds the SAS protocol ones to the party, and uploads replies. Once mutual trust is confirmed (the peer's confirmation arrived) it creates the contact. Returns true once the party is awaiting the out-of-band SAS comparison.

CONCURRENCY: Pump reads the shared server inbox (like ChannelCreation.Pump and the main Receive loop). Do NOT run Receive() concurrently with an in-flight Pump — the main loop's generic OnProtocolMessage handler would consume and delete the SAS reply messages this Pump is waiting for, stalling onboarding. Drive one onboarding exchange at a time, then resume the main receive loop. (A single-owner inbox router is a caller/gateway concern.)

func (*TrustEstablishment) ReceiveParsed added in v0.2.5

func (te *TrustEstablishment) ReceiveParsed(pm *engine.ProtocolMessage) (awaitingSAS bool, err error)

ReceiveParsed feeds one already-decrypted trust protocol message (from the session's receive dispatcher, routed by instance UID) to the exchange, uploads any replies, and finalizes on confirmation. Returns whether the exchange is now awaiting the out-of-band SAS comparison. Unlike Pump it does NOT download — the dispatcher already decrypted and routed the message — so several exchanges can run concurrently off the one receive pass.

func (*TrustEstablishment) ResultContact

func (te *TrustEstablishment) ResultContact() *Contact

ResultContact returns the contact created once mutual trust is confirmed (nil before then).

func (*TrustEstablishment) SAS

func (te *TrustEstablishment) SAS() []byte

SAS returns the 4 digits this party must show the peer (valid once Pump reports AwaitingSAS).

type TrustInfo added in v0.3.0

type TrustInfo struct {
	InstanceUID     [32]byte
	Peer            *engine.CryptoIdentity
	PeerDisplayName string
	SAS             string // the 4 digits to SHOW the peer (valid once Awaiting)
	Inbound         bool
	Awaiting        bool
	Confirming      bool
}

TrustInfo is a snapshot of an in-flight trust exchange for the caller's UX (labelling, SAS entry, and disambiguation when several run at once).

type TrustOrigin

type TrustOrigin struct {
	Type     int
	Mediator []byte // introducer or group-owner identity, if any
	GroupUID []byte // group identifier, if group-based
	Keycloak string // keycloak server, if server-vouched
}

TrustOrigin records one reason a contact is trusted. Fields beyond Type are set per type: Mediator for TrustIntroduction/TrustGroup (the introducer/owner identity), GroupUID for TrustGroup/TrustServerGroupV2 (the shared group), Keycloak for TrustKeycloak.

type UpdateMessage

type UpdateMessage struct {
	Body               string              `json:"body,omitempty"`
	Location           *LocationInfo       `json:"loc,omitempty"`
	Mentions           []UserMention       `json:"um,omitempty"`
	GroupUID           []byte              `json:"guid,omitempty"`
	GroupOwner         []byte              `json:"go,omitempty"`
	GroupV2Identifier  []byte              `json:"gid2,omitempty"`
	OneToOneIdentifier *OneToOneIdentifier `json:"o2oi,omitempty"`
	Reference          *MessageReference   `json:"ref,omitempty"`
}

UpdateMessage edits a previously-sent message (spec §22.2, "Update message request").

type UserMention

type UserMention struct {
	UserIdentity []byte `json:"uid"`
	RangeStart   int    `json:"rs"`
	RangeEnd     int    `json:"re"`
}

UserMention refers to a mentioned contact over a body range (spec §22.2, "User mention"). Ranges are UTF-16 character offsets; start inclusive, end exclusive.

type WebRTCMessage

type WebRTCMessage struct {
	CallIdentifier    string `json:"ci,omitempty"` // UUID string
	MessageType       int    `json:"mt"`
	SerializedPayload string `json:"smp,omitempty"`
}

WebRTCMessage carries call signaling (spec §22.2, "WebRTC message").

Jump to

Keyboard shortcuts

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