Documentation
¶
Overview ¶
Package federation lets independent StrafeChat instances talk to each other.
Model in one paragraph: every instance has a domain and an Ed25519 signing key it publishes at https://<domain>/.well-known/strafe. Users are addressed across instances as `name@domain`, and carry a federated id (FID) `@<id>:<domain>` where <id> is what their *home* instance calls them. A remote user gets a local "shadow" users row so the rest of the codebase keeps working with plain local ids; the FID ↔ shadow mapping lives in users_by_remote. Rooms are mirrored: each participating instance stores its own copy of the room and messages under local ids, tied together by the room's origin (origin_domain, origin_room_id) and per-message origin ids. Every server-to-server request is signed (see signing.go) and verified against the peer's published key.
Index ¶
- Constants
- Variables
- func FormatFID(originID int64, domain string) string
- func NewInfoProvider(session gocqlx.Session, domain string) *infoProvider
- func ParseFID(s string) (originID int64, domain string, err error)
- func RequesterDomain(c fiber.Ctx) string
- func RoomFID(originRoomID int64, originDomain string) string
- func ValidPeerDomain(cfg config.FederationConfig, domain string) bool
- func VerifySignature(pubB64 string, msg []byte, sigB64 string) bool
- func WithExcludedPeer(ctx context.Context, domain string) context.Context
- func WithRelayCapture(ctx context.Context, domain string) (context.Context, *relayCapture)
- type Client
- type DirectoryReply
- type DirectorySource
- type DirectorySpace
- type Discovery
- type EmojiRef
- type Handle
- type Handler
- func (h *Handler) Directory(c fiber.Ctx) error
- func (h *Handler) GetUser(c fiber.Ctx) error
- func (h *Handler) Instance(c fiber.Ctx) error
- func (h *Handler) KeysClaim(c fiber.Ctx) error
- func (h *Handler) KeysQuery(c fiber.Ctx) error
- func (h *Handler) LookupUser(c fiber.Ctx) error
- func (h *Handler) MessageCreate(c fiber.Ctx) error
- func (h *Handler) MessageDelete(c fiber.Ctx) error
- func (h *Handler) MessageEdit(c fiber.Ctx) error
- func (h *Handler) Peers(c fiber.Ctx) error
- func (h *Handler) PinUpdate(c fiber.Ctx) error
- func (h *Handler) Presence(c fiber.Ctx) error
- func (h *Handler) ReactionAdd(c fiber.Ctx) error
- func (h *Handler) ReactionRemove(c fiber.Ctx) error
- func (h *Handler) Relationship(c fiber.Ctx) error
- func (h *Handler) RoomCreate(c fiber.Ctx) error
- func (h *Handler) RoomParticipants(c fiber.Ctx) error
- func (h *Handler) RoomPatch(c fiber.Ctx) error
- func (h *Handler) RoomTyping(c fiber.Ctx) error
- func (h *Handler) SpaceDelete(c fiber.Ctx) error
- func (h *Handler) SpaceEmoji(c fiber.Ctx) error
- func (h *Handler) SpaceInviteCreate(c fiber.Ctx) error
- func (h *Handler) SpaceInvitePreview(c fiber.Ctx) error
- func (h *Handler) SpaceJoin(c fiber.Ctx) error
- func (h *Handler) SpaceJoinListed(c fiber.Ctx) error
- func (h *Handler) SpaceLeave(c fiber.Ctx) error
- func (h *Handler) SpaceManage(c fiber.Ctx) error
- func (h *Handler) SpaceMembers(c fiber.Ctx) error
- func (h *Handler) SpaceMembersList(c fiber.Ctx) error
- func (h *Handler) SpaceMessageCreate(c fiber.Ctx) error
- func (h *Handler) SpaceMessageDelete(c fiber.Ctx) error
- func (h *Handler) SpaceMessageEdit(c fiber.Ctx) error
- func (h *Handler) SpaceMessageGet(c fiber.Ctx) error
- func (h *Handler) SpaceMessagesList(c fiber.Ctx) error
- func (h *Handler) SpaceMessagesSearch(c fiber.Ctx) error
- func (h *Handler) SpacePeers(c fiber.Ctx) error
- func (h *Handler) SpacePin(c fiber.Ctx) error
- func (h *Handler) SpacePinsList(c fiber.Ctx) error
- func (h *Handler) SpaceReactionAdd(c fiber.Ctx) error
- func (h *Handler) SpaceReactionRemove(c fiber.Ctx) error
- func (h *Handler) SpaceRoles(c fiber.Ctx) error
- func (h *Handler) SpaceRooms(c fiber.Ctx) error
- func (h *Handler) SpaceSync(c fiber.Ctx) error
- func (h *Handler) SpaceUpdate(c fiber.Ctx) error
- func (h *Handler) ToDevice(c fiber.Ctx) error
- func (h *Handler) UserUpdated(c fiber.Ctx) error
- func (h *Handler) VoiceCall(c fiber.Ctx) error
- func (h *Handler) VoiceDecline(c fiber.Ctx) error
- func (h *Handler) VoiceJoin(c fiber.Ctx) error
- func (h *Handler) VoiceLeave(c fiber.Ctx) error
- func (h *Handler) VoiceRing(c fiber.Ctx) error
- func (h *Handler) VoiceSelf(c fiber.Ctx) error
- func (h *Handler) VoiceState(c fiber.Ctx) error
- type InstanceInfo
- type KeysClaim
- type KeysQuery
- type MessageDelete
- type MessageEdit
- type MessageEvent
- type MessageMapping
- type MessageRef
- type OutboxEntry
- type ParticipantsUpdate
- type Peer
- type PinEvent
- type PinItem
- type PinsQuery
- type PinsReply
- type PresenceEvent
- type Profile
- type ProfileUpdate
- type ReactionEvent
- type RelationshipEvent
- type RelayEvent
- type Repository
- type RoomAnnounce
- type RoomAnnounceReply
- type RoomMapping
- type RoomPatch
- type RoomRef
- type Service
- func (s *Service) AfterCallChanged(ctx context.Context, room *rooms.RoomWithParticipants, event string, ...)
- func (s *Service) AfterMessageCreated(ctx context.Context, roomID int64, participants []int64, m *messages.Message)
- func (s *Service) AfterMessageDeleted(ctx context.Context, roomID int64, participants []int64, msgID int64)
- func (s *Service) AfterMessageEdited(ctx context.Context, roomID int64, participants []int64, m *messages.Message)
- func (s *Service) AfterMessagePinned(ctx context.Context, roomID int64, participants []int64, msgID, userID int64, ...)
- func (s *Service) AfterParticipantsChanged(ctx context.Context, rwp *rooms.RoomWithParticipants, removed []int64)
- func (s *Service) AfterPresenceChanged(ctx context.Context, u *auth.User)
- func (s *Service) AfterProfileUpdated(ctx context.Context, u *auth.User)
- func (s *Service) AfterReactionAdded(ctx context.Context, roomID int64, participants []int64, msgID, userID int64, ...)
- func (s *Service) AfterReactionRemoved(ctx context.Context, roomID int64, participants []int64, msgID, userID int64, ...)
- func (s *Service) AfterRelationshipAccepted(_ context.Context, actor, target *auth.User)
- func (s *Service) AfterRelationshipRemoved(_ context.Context, actor, target *auth.User)
- func (s *Service) AfterRelationshipRequested(_ context.Context, actor, target *auth.User)
- func (s *Service) AfterRoomCreated(ctx context.Context, rwp *rooms.RoomWithParticipants)
- func (s *Service) AfterRoomUpdated(ctx context.Context, rwp *rooms.RoomWithParticipants)
- func (s *Service) AfterSpaceDeleted(ctx context.Context, sp *spaces.Space)
- func (s *Service) AfterSpaceEmojiChanged(ctx context.Context, spaceID int64, e *spaces.SpaceEmoji, deleted bool)
- func (s *Service) AfterSpaceMemberAdded(ctx context.Context, spaceID int64, m *spaces.SpaceMember)
- func (s *Service) AfterSpaceMemberRemoved(ctx context.Context, spaceID, userID int64, how string)
- func (s *Service) AfterSpaceMemberUpdated(ctx context.Context, spaceID int64, m *spaces.SpaceMember)
- func (s *Service) AfterSpaceRoleChanged(ctx context.Context, spaceID int64, role *spaces.SpaceRole, deleted bool)
- func (s *Service) AfterSpaceRoomChanged(ctx context.Context, spaceID int64, room *rooms.Room, ...)
- func (s *Service) AfterSpaceRoomsReordered(ctx context.Context, spaceID int64, list []*rooms.Room)
- func (s *Service) AfterSpaceUpdated(ctx context.Context, sp *spaces.Space)
- func (s *Service) AfterTyping(ctx context.Context, roomID, userID int64)
- func (s *Service) AfterVoiceStateChanged(ctx context.Context, room *rooms.RoomWithParticipants, st *voice.State, ...)
- func (s *Service) ClaimRemote(ctx context.Context, domain string, req map[string]map[string]string) (*devices.ClaimKeysOutput, error)
- func (s *Service) CreateRemote(ctx context.Context, origin string, room *rooms.Room, userID int64, ...) (*messages.Message, error)
- func (s *Service) CreateRemoteInvite(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.SpaceInvite, error)
- func (s *Service) DeclineRemoteCall(ctx context.Context, origin string, room *rooms.RoomWithParticipants, ...)
- func (s *Service) DeleteRemote(ctx context.Context, origin string, room *rooms.Room, userID, msgID int64) error
- func (s *Service) Domain() string
- func (s *Service) EditRemote(ctx context.Context, origin string, room *rooms.Room, userID, msgID int64, ...) (*messages.Message, error)
- func (s *Service) Enabled() bool
- func (s *Service) EnsureShadow(ctx context.Context, domain string, p Profile) (*auth.User, error)
- func (s *Service) FIDOf(u *auth.User) string
- func (s *Service) FetchDirectory(ctx context.Context, domain string) ([]discover.RemoteListing, error)
- func (s *Service) GetRemote(ctx context.Context, origin string, room *rooms.Room, userID, msgID int64) (*messages.Message, []messages.ReactionSummary, error)
- func (s *Service) Info() *InstanceInfo
- func (s *Service) IsLocalServer(server string) bool
- func (s *Service) JoinListedSpace(ctx context.Context, domain string, originSpaceID, userID int64) (*spaces.Space, error)
- func (s *Service) JoinRemoteSpace(ctx context.Context, domain, code string, user *auth.User) (*spaces.Space, error)
- func (s *Service) JoinRemoteVoice(ctx context.Context, origin string, room *rooms.RoomWithParticipants, ...) (*voice.RemoteJoin, error)
- func (s *Service) LeaveRemoteSpace(ctx context.Context, origin string, spaceID int64, user *auth.User) error
- func (s *Service) LeaveRemoteVoice(ctx context.Context, origin string, room *rooms.RoomWithParticipants, ...)
- func (s *Service) ListAfterRemote(ctx context.Context, origin string, room *rooms.Room, userID, afterID int64, ...) ([]messages.Message, map[int64][]messages.ReactionSummary, error)
- func (s *Service) ListAroundRemote(ctx context.Context, origin string, room *rooms.Room, userID, aroundID int64, ...) ([]messages.Message, map[int64][]messages.ReactionSummary, error)
- func (s *Service) ListPinsRemote(ctx context.Context, origin string, room *rooms.Room, userID int64) ([]messages.PinnedMessage, error)
- func (s *Service) ListRemote(ctx context.Context, origin string, room *rooms.Room, userID int64, ...) ([]messages.Message, map[int64][]messages.ReactionSummary, error)
- func (s *Service) LocalFID(userID int64) string
- func (s *Service) PeerDomains(ctx context.Context) []string
- func (s *Service) PinRemote(ctx context.Context, origin string, room *rooms.Room, userID, msgID int64, ...) error
- func (s *Service) PreviewRemoteInvite(ctx context.Context, domain, code string) (*spaces.InvitePreview, error)
- func (s *Service) ProfileOf(u *auth.User) Profile
- func (s *Service) QueryRemote(ctx context.Context, domain string, req map[string][]string) (*devices.QueryKeysOutput, error)
- func (s *Service) ReactRemote(ctx context.Context, origin string, room *rooms.Room, userID, msgID int64, ...) ([]messages.ReactionSummary, error)
- func (s *Service) RemoteAddMember(ctx context.Context, origin string, spaceID int64, actor, user *auth.User) (bool, error)
- func (s *Service) RemoteCreateEmoji(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.SpaceEmoji, error)
- func (s *Service) RemoteCreateRole(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.SpaceRole, error)
- func (s *Service) RemoteCreateRoom(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*rooms.Room, error)
- func (s *Service) RemoteDeleteEmoji(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.SpaceEmoji, error)
- func (s *Service) RemoteDeleteInvite(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteDeleteRole(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteDeleteRoom(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteDeleteSpace(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteInstallBot(ctx context.Context, origin string, spaceID int64, user, bot *auth.User, ...) (int64, error)
- func (s *Service) RemoteListAuditLog(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) ([]spaces.SpaceAuditEntry, map[int64]*auth.User, error)
- func (s *Service) RemoteListBans(ctx context.Context, origin string, spaceID int64, user *auth.User) ([]spaces.SpaceBan, map[int64]*auth.User, error)
- func (s *Service) RemoteListInvites(ctx context.Context, origin string, spaceID int64, user *auth.User) ([]spaces.SpaceInvite, map[int64]*auth.User, error)
- func (s *Service) RemoteModerate(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteMoveChannel(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteOrigin(ctx context.Context, room *rooms.Room) string
- func (s *Service) RemoteOverride(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemotePatchSpace(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.Space, error)
- func (s *Service) RemoteRenameEmoji(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.SpaceEmoji, error)
- func (s *Service) RemoteReorderRooms(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteSetMemberRoles(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RemoteSetSpaceImage(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.Space, error)
- func (s *Service) RemoteSpaceOrigin(ctx context.Context, spaceID int64) string
- func (s *Service) RemoteTransferOwnership(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.Space, error)
- func (s *Service) RemoteUpdateRole(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) (*spaces.SpaceRole, error)
- func (s *Service) RemoteUpdateRoom(ctx context.Context, origin string, spaceID int64, user *auth.User, ...) error
- func (s *Service) RequireInstance() fiber.Handler
- func (s *Service) ResolveHandle(ctx context.Context, raw string) (*auth.User, error)
- func (s *Service) ResolveLocalID(ctx context.Context, fid string) (int64, error)
- func (s *Service) ResyncMirror(ctx context.Context, m *SpaceMapping) error
- func (s *Service) ResyncRemote(ctx context.Context, origin string, spaceID int64) error
- func (s *Service) RingRemoteCall(ctx context.Context, origin string, room *rooms.RoomWithParticipants, ...)
- func (s *Service) RoomFederation(ctx context.Context, roomID int64) *rooms.Federation
- func (s *Service) RoomFederations(ctx context.Context, roomIDs []int64) map[int64]*rooms.Federation
- func (s *Service) SearchRemote(ctx context.Context, origin string, room *rooms.Room, userID int64, ...) (*messages.SearchResult, error)
- func (s *Service) SearchSpaceRemote(ctx context.Context, origin string, spaceID, userID int64, ...) (*messages.SpaceSearchResult, error)
- func (s *Service) SendToDeviceRemote(ctx context.Context, domain string, senderUserID, senderDeviceID int64, ...) error
- func (s *Service) SetDirectory(d DirectorySource)
- func (s *Service) SetSpaces(svc *spaces.Service)
- func (s *Service) SetVoice(v *voice.Service)
- func (s *Service) SpaceFederation(ctx context.Context, spaceID int64) *spaces.SpaceFederation
- func (s *Service) StartMaintenance(ctx context.Context)
- func (s *Service) UpdateRemoteVoiceSelf(ctx context.Context, origin string, room *rooms.RoomWithParticipants, ...)
- type Signer
- type SoftwareInfo
- type SpaceDeleteEvent
- type SpaceEmojiEvent
- type SpaceEmojiWire
- type SpaceInfo
- type SpaceInvitePreviewReply
- type SpaceInviteReply
- type SpaceInviteRequest
- type SpaceJoinListedRequest
- type SpaceJoinRequest
- type SpaceManageReply
- type SpaceManageRequest
- type SpaceMapping
- type SpaceMemberEvent
- type SpaceMemberWire
- type SpaceMembersQuery
- type SpaceMembersReply
- type SpaceMessageEditRequest
- type SpaceMessageRequest
- type SpaceMessageRequestRef
- type SpaceMessagesQuery
- type SpaceMessagesReply
- type SpaceOverrideWire
- type SpacePeer
- type SpacePeerEvent
- type SpaceReactionReply
- type SpaceRef
- type SpaceRoleEvent
- type SpaceRoleWire
- type SpaceRoomEvent
- type SpaceRoomOrder
- type SpaceRoomWire
- type SpaceSearchQuery
- type SpaceSearchReply
- type SpaceSnapshot
- type SpaceSyncRequest
- type SpaceUpdateEvent
- type SpaceUserRequest
- type StatusError
- type ThreadWire
- type ToDevice
- type TypingEvent
- type VoiceCall
- type VoiceCallEvent
- type VoiceJoinReply
- type VoiceJoinRequest
- type VoiceRing
- type VoiceSelfUpdate
- type VoiceState
- type VoiceStateEvent
- type VoiceUserRequest
Constants ¶
const ( HeaderInstance = "X-Strafe-Instance" HeaderTimestamp = "X-Strafe-Timestamp" HeaderNonce = "X-Strafe-Nonce" HeaderSignature = "X-Strafe-Signature" // MaxClockSkewSeconds bounds how old/new a request timestamp may be. MaxClockSkewSeconds = 300 // BasePath is where inbound federation routes are mounted on the API. BasePath = "/federation/v1" )
Request signature scheme ("strafe-fed-v1").
Headers on every server-to-server request:
X-Strafe-Instance: sender's domain X-Strafe-Timestamp: unix seconds (receiver rejects if more than MaxClockSkew away) X-Strafe-Nonce: random string, unique per request (receiver rejects replays) X-Strafe-Signature: <key_id>=<base64 ed25519 signature>
The signature covers the method, the federation-relative path (what follows /federation/v1, query string included - so reverse proxies that mount the API under a prefix don't change what's signed), the timestamp, the nonce and the SHA-256 of the body.
const KeyID = "ed25519:1"
KeyID identifies the signing key in /.well-known/strafe and request signatures. Bump when the format of the signed payload changes.
const LegacyServer = "strafe.internal"
LegacyServer is the synthetic server name the E2EE engine used before federation existed (@<id>:strafe.internal). Treated as "this instance" everywhere so an instance that never enables federation keeps working with clients that still send it.
const WellKnownPath = "/.well-known/strafe"
WellKnownPath is where InstanceInfo is served, relative to https://<domain>.
Variables ¶
var ( ErrInvalidHandle = errors.New("invalid handle - expected name@domain") ErrInvalidFID = errors.New("invalid federated id - expected @id:domain") ErrPeerNotAllowed = errors.New("that instance is not allowed by this server's federation policy") ErrFederationOff = errors.New("federation is not enabled on this instance") ErrRemoteUserNotFound = errors.New("no such user on that instance") )
var ErrPayloadTooLarge = errors.New("federation payload exceeds limits")
ErrPayloadTooLarge is returned for inbound federation payloads over the caps.
Functions ¶
func NewInfoProvider ¶
NewInfoProvider builds the read-only federation view; domain is this instance's own.
func RequesterDomain ¶
RequesterDomain is the verified peer domain of an inbound federation request.
func RoomFID ¶
RoomFID is the global room identity the E2EE engine keys Megolm sessions by: !<origin_room_id>:<origin_domain>. Every participating instance must agree on it.
func ValidPeerDomain ¶
func ValidPeerDomain(cfg config.FederationConfig, domain string) bool
ValidPeerDomain reports whether a domain may be looked up at all. With AllowInsecure off (production) it also refuses IP literals and loopback/link-local names, so a forged X-Strafe-Instance header cannot point discovery at this host's own network (cloud metadata endpoints, internal services).
func VerifySignature ¶
VerifySignature checks sigB64 over msg with a peer's base64 public key.
func WithExcludedPeer ¶
WithExcludedPeer marks the instance whose request is being served, so the relays the request causes skip it: it applies the reply itself, and a copy would race it.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client makes signed requests to peer instances.
func NewClient ¶
func NewClient(cfg config.FederationConfig, signer *Signer, discovery *Discovery) *Client
func (*Client) Do ¶
func (c *Client) Do(ctx context.Context, domain, method, fedPath string, body any, out any) (int, error)
Do sends a signed JSON request to domain's federation endpoint. fedPath is relative to /federation/v1 (e.g. "/rooms" or "/users/lookup?username=a"). A JSON 2xx body is decoded into out when out is non-nil.
type DirectoryReply ¶
type DirectoryReply struct {
Spaces []DirectorySpace `json:"spaces"`
}
DirectoryReply: GET /discover - the spaces this instance lists and shares.
type DirectorySource ¶
type DirectorySource interface {
SharedListings(ctx context.Context) ([]discover.RemoteListing, error)
// lets a peer's user join it without an invite.
SharesSpace(ctx context.Context, spaceID int64) (bool, error)
}
DirectorySource is the local Discover module, as this engine needs it. Set from route setup; nil leaves the endpoints answering "nothing listed", which is also what an instance with DISCOVER_FEDERATION off wants.
type DirectorySpace ¶
type DirectorySpace struct {
SpaceID string `json:"space_id"`
Name string `json:"name"`
NameAcronym string `json:"name_acronym,omitempty"`
Icon string `json:"icon,omitempty"`
Banner string `json:"banner,omitempty"`
Description string `json:"description,omitempty"`
Tagline string `json:"tagline,omitempty"`
Tags []string `json:"tags,omitempty"`
MemberCount int `json:"member_count"`
OnlineCount int `json:"online_count"`
}
DirectorySpace is one card. Ids are the serving instance's own.
type Discovery ¶
type Discovery struct {
// contains filtered or unexported fields
}
Discovery resolves a peer domain to its InstanceInfo, with an in-memory cache.
func NewDiscovery ¶
func NewDiscovery(cfg config.FederationConfig) *Discovery
type EmojiRef ¶
type EmojiRef struct {
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
Animated bool `json:"animated,omitempty"`
}
EmojiRef describes a custom emoji an event uses, so an instance that has never seen the emoji's space can still render it (see content.go). The id is the emoji's own.
type Handle ¶
Handle is a user address as people type it: name@domain (domain optional = local). Usernames are unique per instance, so the name alone identifies someone there.
func ParseHandle ¶
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler serves the inbound side of /federation/v1 (every route except /instance sits behind Service.RequireInstance).
func NewHandler ¶
func (*Handler) Directory ¶
Directory GET /discover - serves this instance's shared listings to a peer.
func (*Handler) Instance ¶
Instance serves the instance document (also mounted at /.well-known/strafe).
func (*Handler) LookupUser ¶
LookupUser GET /users/lookup?username= - a local user's profile.
func (*Handler) MessageCreate ¶
MessageCreate POST /rooms/messages.
func (*Handler) MessageDelete ¶
MessageDelete POST /rooms/messages/delete.
func (*Handler) MessageEdit ¶
MessageEdit PATCH /rooms/messages.
func (*Handler) Peers ¶
Peers GET /federation/peers (client-authenticated, not S2S): instances we've talked to.
func (*Handler) PinUpdate ¶
PinUpdate serves POST /rooms/pins: one of the requesting instance's users pinned or unpinned a message in a shared room (a PM, or a channel whose origin is the requester).
func (*Handler) Presence ¶
Presence POST /users/presence - how a user on the requesting instance now appears to others. Applied to their shadow row (so lists and READY carry it) and fanned out to their local friends like a local presence change.
func (*Handler) Relationship ¶
Relationship POST /relationships - a friend request, acceptance or teardown from a user on the requesting instance towards one of ours.
func (*Handler) RoomCreate ¶
RoomCreate POST /rooms - mirror a room the requesting instance created.
func (*Handler) RoomParticipants ¶
RoomParticipants PUT /rooms/participants - reconcile the member set.
func (*Handler) RoomTyping ¶
RoomTyping POST /rooms/typing.
func (*Handler) SpaceDelete ¶
SpaceDelete POST /spaces/delete - the origin deleted the space.
func (*Handler) SpaceEmoji ¶
SpaceEmoji POST /spaces/emoji.
func (*Handler) SpaceInviteCreate ¶
SpaceInviteCreate POST /spaces/invites.
func (*Handler) SpaceInvitePreview ¶
SpaceInvitePreview GET /spaces/invites/:code - what a local invite code leads to.
func (*Handler) SpaceJoin ¶
SpaceJoin POST /spaces/join - a user on the requesting instance redeems an invite. The answer is the whole space, so the requester can build its mirror in one step.
func (*Handler) SpaceJoinListed ¶
SpaceJoinListed POST /spaces/join_listed - add a peer's user to a space listed here. The listing is checked again on this side: a peer holding a stale card, or inventing one, cannot use it to get into a space that is not publicly listed.
func (*Handler) SpaceLeave ¶
SpaceLeave POST /spaces/leave.
func (*Handler) SpaceManage ¶
SpaceManage POST /spaces/manage - run a management operation as a member elsewhere.
func (*Handler) SpaceMembers ¶
SpaceMembers POST /spaces/members.
func (*Handler) SpaceMembersList ¶
SpaceMembersList POST /spaces/members/list - a mirror fetches the next page of members.
func (*Handler) SpaceMessageCreate ¶
SpaceMessageCreate POST /spaces/messages.
func (*Handler) SpaceMessageDelete ¶
SpaceMessageDelete POST /spaces/messages/delete.
func (*Handler) SpaceMessageEdit ¶
SpaceMessageEdit PATCH /spaces/messages.
func (*Handler) SpaceMessageGet ¶
SpaceMessageGet POST /spaces/messages/get.
func (*Handler) SpaceMessagesList ¶
SpaceMessagesList POST /spaces/messages/list - a page of history as the member sees it.
func (*Handler) SpaceMessagesSearch ¶
SpaceMessagesSearch POST /spaces/messages/search - the origin's side: search a hosted space (or one channel of it) as the asking member.
func (*Handler) SpacePeers ¶
SpacePeers POST /spaces/peers - the origin says an instance joined or left the space.
func (*Handler) SpacePin ¶
SpacePin POST /spaces/pins: a mirror's member pins or unpins in a channel hosted here. The origin checks Manage Messages for them, posts the notice and relays to every other mirror; the reply is the event as applied, so the asking mirror records the same pinned_at.
func (*Handler) SpacePinsList ¶
SpacePinsList POST /spaces/pins/list - a hosted channel's pin list as the member sees it.
func (*Handler) SpaceRoles ¶
SpaceRoles POST /spaces/roles.
func (*Handler) SpaceRooms ¶
SpaceRooms POST /spaces/rooms.
func (*Handler) SpaceUpdate ¶
SpaceUpdate POST /spaces/update.
func (*Handler) ToDevice ¶
ToDevice POST /to_device - Olm/Megolm to-device traffic for this instance's users.
func (*Handler) UserUpdated ¶
UserUpdated POST /users/update - refresh a shadow and tell local rooms.
func (*Handler) VoiceCall ¶
VoiceCall POST /rooms/voice/call - mirror a call event the origin reported.
func (*Handler) VoiceDecline ¶
VoiceDecline POST /rooms/voice/decline.
func (*Handler) VoiceJoin ¶
VoiceJoin POST /rooms/voice/join - mint a token for one of the requesting instance's users in a call this instance hosts.
func (*Handler) VoiceLeave ¶
VoiceLeave POST /rooms/voice/leave.
type InstanceInfo ¶
type InstanceInfo struct {
Domain string `json:"domain"`
Version int `json:"version"`
APIURL string `json:"api_url"`
GatewayURL string `json:"gateway_url,omitempty"`
FederationURL string `json:"federation_url"`
KeyID string `json:"key_id"`
PublicKey string `json:"public_key"`
Software SoftwareInfo `json:"software"`
}
InstanceInfo is what an instance publishes at /.well-known/strafe (and mirrors at /federation/v1/instance): enough for a peer to find its federation endpoint and verify its signatures, and for a client to discover where to connect.
type KeysQuery ¶
KeysQuery / KeysClaim mirror the Matrix-shaped device endpoints, scoped to the receiver's own users.
type MessageDelete ¶
type MessageDelete struct {
Room RoomRef `json:"room"`
Message MessageRef `json:"message"`
}
MessageDelete: POST /rooms/messages/delete.
type MessageEdit ¶
type MessageEdit struct {
Room RoomRef `json:"room"`
Message MessageRef `json:"message"`
Ciphertext string `json:"ciphertext,omitempty"`
Plaintext string `json:"plaintext,omitempty"`
Emojis []EmojiRef `json:"emojis,omitempty"`
}
MessageEdit: PATCH /rooms/messages.
type MessageEvent ¶
type MessageEvent struct {
Room RoomRef `json:"room"`
Message MessageRef `json:"message"`
Sender *Profile `json:"sender,omitempty"`
SenderDeviceID string `json:"sender_device_id,omitempty"`
Ciphertext string `json:"ciphertext,omitempty"`
Plaintext string `json:"plaintext,omitempty"`
ReplyTo *MessageRef `json:"reply_to,omitempty"`
Mentions []string `json:"mentions,omitempty"`
MentionRoles []string `json:"mention_roles,omitempty"` // space channels: the origin's role ids
MentionEveryone bool `json:"mention_everyone,omitempty"`
Attachments []messages.Attachment `json:"attachments,omitempty"`
// Emojis describes the custom emoji the text uses; mentions in the text are <@FID>.
Emojis []EmojiRef `json:"emojis,omitempty"`
SystemType string `json:"system_type,omitempty"`
SystemPayload string `json:"system_payload,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
// Reactions is set on history read from a space's origin (as the asking user sees
// them); never on relays.
Reactions []messages.ReactionSummary `json:"reactions,omitempty"`
// Pinned state, carried on history and pin lists read from a space's origin.
PinnedAt *time.Time `json:"pinned_at,omitempty"`
PinnedBy string `json:"pinned_by,omitempty"` // FID
}
MessageEvent: POST /rooms/messages - a new message (including system messages, which have SystemType set and no sender).
type MessageMapping ¶
type MessageMapping struct {
RoomID int64 `db:"room_id"`
MessageID int64 `db:"message_id"`
OriginDomain string `db:"origin_domain"`
OriginMessageID int64 `db:"origin_message_id"`
}
MessageMapping ties a local message to the id its origin instance uses.
type MessageRef ¶
type OutboxEntry ¶
type OutboxEntry struct {
Domain string `db:"domain"`
Seq int64 `db:"seq"`
Method string `db:"method"`
Path string `db:"path"`
Body string `db:"body"`
CreatedAt time.Time `db:"created_at"`
}
OutboxEntry is one relay waiting to be delivered to a peer (see outbox.go).
type ParticipantsUpdate ¶
type ParticipantsUpdate struct {
Room RoomRef `json:"room"`
Participants []Profile `json:"participants"`
Removed []string `json:"removed,omitempty"`
}
ParticipantsUpdate: PUT /rooms/participants - the full current member set plus who left.
type Peer ¶
type Peer struct {
Domain string `db:"domain"`
KeyID string `db:"key_id"`
PublicKey string `db:"public_key"`
FederationURL string `db:"federation_url"`
APIURL string `db:"api_url"`
FirstSeen time.Time `db:"first_seen"`
LastSeen time.Time `db:"last_seen"`
Blocked bool `db:"blocked"`
// LastError/LastFailure: set while the outbox cannot deliver to the peer, cleared by
// the next relay it takes.
LastError string `db:"last_error"`
LastFailure *time.Time `db:"last_failure"`
}
Peer is a remote instance we've talked to.
type PinEvent ¶
type PinEvent struct {
Room RoomRef `json:"room"`
Message MessageRef `json:"message"`
User string `json:"user"` // FID, must belong to the requesting instance
PinnedAt time.Time `json:"pinned_at"`
Remove bool `json:"remove,omitempty"`
}
PinEvent: POST /rooms/pins (to a PM's other instances and a channel's mirrors) and POST /spaces/pins (to a channel's origin, by a mirror): User pinned - or, with Remove, unpinned - Message in Room at PinnedAt. The origin answers /spaces/pins with the event as applied (its PinnedAt).
type PinItem ¶
type PinItem struct {
PinnedAt time.Time `json:"pinned_at"`
PinnedBy string `json:"pinned_by,omitempty"` // FID
Message MessageEvent `json:"message"`
}
type PinsQuery ¶
type PinsQuery struct {
Room RoomRef `json:"room"`
User string `json:"user"` // FID of the member asking
}
PinsQuery / PinsReply: POST /spaces/pins/list - a hosted channel's pin list from its origin, as the asking member sees it, newest pin first.
type PresenceEvent ¶
type PresenceEvent struct {
User string `json:"user"` // FID, must belong to the requesting instance
Presence auth.PublicPresence `json:"presence"`
}
PresenceEvent: POST /users/presence - how a user on the sending instance now appears to others (invisible already reads as offline), sent to the home instances of their remote friends.
type Profile ¶
type Profile struct {
FID string `json:"fid"`
Username string `json:"username"`
DisplayName string `json:"display_name"`
Avatar string `json:"avatar,omitempty"`
Banner string `json:"banner,omitempty"`
Bio string `json:"bio,omitempty"`
AboutMe string `json:"about_me,omitempty"`
Pronouns string `json:"pronouns,omitempty"`
Bot bool `json:"bot,omitempty"`
}
Profile is a user as one instance describes them to another. Carrying the profile with every reference means a receiver can create the shadow row without a round trip.
type ProfileUpdate ¶
type ProfileUpdate struct {
User Profile `json:"user"`
}
ProfileUpdate: POST /users/update - a user on the sending instance changed their profile.
type ReactionEvent ¶
type ReactionEvent struct {
Room RoomRef `json:"room"`
Message MessageRef `json:"message"`
User string `json:"user"` // FID, must belong to the requesting instance
Emoji string `json:"emoji"`
EmojiRef *EmojiRef `json:"emoji_ref,omitempty"`
}
ReactionEvent: POST /rooms/reactions and POST /rooms/reactions/delete - a user on the sending instance reacted to (or withdrew a reaction from) a message in a shared room. A "custom:<id>" emoji is a custom emoji id; EmojiRef describes it so the receiving instance can render it even when it has never seen the emoji's space (content.go).
type RelationshipEvent ¶
type RelationshipEvent struct {
Action string `json:"action"` // request | accept | remove
Actor Profile `json:"actor"`
Target string `json:"target"` // FID of a user on the receiving instance
}
RelationshipEvent: POST /relationships - a user on the sending instance sent a friend request to, accepted one from, or dropped one of the receiver's users. "remove" covers every teardown (withdrawn, declined, unfriended, blocked): the receiver's own state says which it was, and a block itself is never announced.
type RelayEvent ¶
type RelayEvent struct {
Method string `json:"method"`
Path string `json:"path"`
Body json.RawMessage `json:"body"`
}
RelayEvent is one relay as it would have gone out: the request a peer would have received. The origin hands these back in the reply to a request that caused them, so the asking instance applies exactly what every other mirror gets.
type Repository ¶
type Repository interface {
GetRoomMapping(ctx context.Context, roomID int64) (*RoomMapping, error)
// GetRoomMappings is GetRoomMapping for many rooms in one query (missing ids absent).
GetRoomMappings(ctx context.Context, roomIDs []int64) (map[int64]*RoomMapping, error)
GetRoomByOrigin(ctx context.Context, originDomain string, originRoomID int64) (*RoomMapping, error)
PutRoomMapping(ctx context.Context, m *RoomMapping) error
DeleteRoomMapping(ctx context.Context, m *RoomMapping) error
GetSpaceMapping(ctx context.Context, spaceID int64) (*SpaceMapping, error)
GetSpaceByOrigin(ctx context.Context, originDomain string, originSpaceID int64) (*SpaceMapping, error)
PutSpaceMapping(ctx context.Context, m *SpaceMapping) error
DeleteSpaceMapping(ctx context.Context, m *SpaceMapping) error
// ListSpaceMappings scans every mapping (mirrors and hosted spaces alike).
ListSpaceMappings(ctx context.Context) ([]SpaceMapping, error)
// Space peers: the instances mirroring a space this instance hosts.
ListSpacePeers(ctx context.Context, spaceID int64) ([]string, error)
IsSpacePeer(ctx context.Context, spaceID int64, domain string) (bool, error)
AddSpacePeer(ctx context.Context, spaceID int64, domain string) error
RemoveSpacePeer(ctx context.Context, spaceID int64, domain string) error
DeleteSpacePeers(ctx context.Context, spaceID int64) error
GetMessageMapping(ctx context.Context, roomID, messageID int64) (*MessageMapping, error)
GetMessageByOrigin(ctx context.Context, originDomain string, originMessageID int64) (*MessageMapping, error)
PutMessageMapping(ctx context.Context, m *MessageMapping) error
GetPeer(ctx context.Context, domain string) (*Peer, error)
UpsertPeer(ctx context.Context, p *Peer) error
ListPeers(ctx context.Context) ([]Peer, error)
MarkPeerFailure(ctx context.Context, domain, message string, at time.Time) error
ClearPeerFailure(ctx context.Context, domain string) error
// Outbox: relays waiting for delivery, per peer, oldest first.
PutOutbox(ctx context.Context, e *OutboxEntry, ttl time.Duration) error
ListOutbox(ctx context.Context, domain string, limit int) ([]OutboxEntry, error)
DeleteOutbox(ctx context.Context, domain string, seq int64) error
ListOutboxDomains(ctx context.Context) ([]string, error)
CountOutbox(ctx context.Context, domain string) (int, error)
}
func NewRepository ¶
func NewRepository(session gocqlx.Session) Repository
type RoomAnnounce ¶
type RoomAnnounce struct {
Room RoomRef `json:"room"`
Type int `json:"type"`
Name string `json:"name,omitempty"`
E2EEEnabled bool `json:"e2ee_enabled"`
Creator string `json:"creator,omitempty"`
Participants []Profile `json:"participants"`
}
RoomAnnounce: POST /rooms - the origin instance tells a peer about a new room some of its users are in. Idempotent on (origin_domain, origin_room_id).
type RoomAnnounceReply ¶
type RoomAnnounceReply struct {
RoomID string `json:"room_id"`
}
RoomAnnounceReply returns the receiver's local room id (for diagnostics only).
type RoomMapping ¶
type RoomMapping struct {
RoomID int64 `db:"room_id"`
OriginDomain string `db:"origin_domain"`
OriginRoomID int64 `db:"origin_room_id"`
CreatedAt time.Time `db:"created_at"`
}
RoomMapping ties a local room to its global identity.
type RoomPatch ¶
type RoomPatch struct {
Room RoomRef `json:"room"`
Name *string `json:"name,omitempty"`
E2EEEnabled *bool `json:"e2ee_enabled,omitempty"`
}
RoomPatch: PATCH /rooms - name / E2EE setting changes.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is the federation engine: outbound relays (implements rooms.Federator, messages.Federator, spaces.Federator, devices.KeyRouter/FIDResolver) plus the state inbound handlers use.
func New ¶
New builds the engine with its own repository/service instances (stateless wrappers over the same Scylla session the API uses).
func NewWithExistingKey ¶
func NewWithExistingKey(cfg *config.Config, session gocqlx.Session, rdb *redis.Client) (*Service, error)
NewWithExistingKey is New for a process that shares the API's signing key but must never create it (the gateway): until the API has written the key this fails instead of minting a second identity that no peer would accept.
func (*Service) AfterCallChanged ¶
func (*Service) AfterMessageCreated ¶
func (*Service) AfterMessageDeleted ¶
func (*Service) AfterMessageEdited ¶
func (*Service) AfterMessagePinned ¶
func (s *Service) AfterMessagePinned(ctx context.Context, roomID int64, participants []int64, msgID, userID int64, at time.Time, remove bool)
AfterMessagePinned tells the room's other instances about a pin or unpin made here: a PM's other participants' instances, or every mirror of a channel hosted here.
func (*Service) AfterParticipantsChanged ¶
func (*Service) AfterPresenceChanged ¶
AfterPresenceChanged tells the home instance of each remote friend, and every instance sharing a space with the user, how the user now appears to others - the same audience the local gateway tells.
func (*Service) AfterProfileUpdated ¶
AfterProfileUpdated tells every instance that holds a shadow of this user (any peer sharing a room or a space with them, or the home of a remote friend) about the new profile.
func (*Service) AfterReactionAdded ¶
func (*Service) AfterReactionRemoved ¶
func (*Service) AfterRelationshipAccepted ¶
func (*Service) AfterRelationshipRemoved ¶
func (*Service) AfterRelationshipRequested ¶
func (*Service) AfterRoomCreated ¶
func (s *Service) AfterRoomCreated(ctx context.Context, rwp *rooms.RoomWithParticipants)
func (*Service) AfterRoomUpdated ¶
func (s *Service) AfterRoomUpdated(ctx context.Context, rwp *rooms.RoomWithParticipants)
func (*Service) AfterSpaceDeleted ¶
func (*Service) AfterSpaceEmojiChanged ¶
func (*Service) AfterSpaceMemberAdded ¶
func (*Service) AfterSpaceMemberRemoved ¶
func (*Service) AfterSpaceMemberUpdated ¶
func (*Service) AfterSpaceRoleChanged ¶
func (*Service) AfterSpaceRoomChanged ¶
func (*Service) AfterSpaceRoomsReordered ¶
func (*Service) AfterSpaceUpdated ¶
func (*Service) AfterTyping ¶
func (*Service) AfterVoiceStateChanged ¶
func (*Service) ClaimRemote ¶
func (*Service) CreateRemote ¶
func (*Service) CreateRemoteInvite ¶
func (*Service) DeclineRemoteCall ¶
func (*Service) DeleteRemote ¶
func (*Service) EditRemote ¶
func (*Service) EnsureShadow ¶
EnsureShadow creates or refreshes the local shadow row for a remote user. The profile's FID must be at `domain` - a peer can only vouch for its own users.
func (*Service) FIDOf ¶
FIDOf is a user's federated id: their home instance's id for them at their home domain.
func (*Service) FetchDirectory ¶
func (s *Service) FetchDirectory(ctx context.Context, domain string) ([]discover.RemoteListing, error)
FetchDirectory asks one peer what it lists.
func (*Service) Info ¶
func (s *Service) Info() *InstanceInfo
Info is this instance's /.well-known/strafe document.
func (*Service) IsLocalServer ¶
IsLocalServer: the server part of @id:server names this instance (or the pre-federation synthetic name, or nothing at all).
func (*Service) JoinListedSpace ¶
func (s *Service) JoinListedSpace(ctx context.Context, domain string, originSpaceID, userID int64) (*spaces.Space, error)
JoinListedSpace joins a space `domain` lists publicly, on behalf of a local user, and builds this instance's mirror of it from the answer - the same path an invite join takes.
func (*Service) JoinRemoteSpace ¶
func (*Service) JoinRemoteVoice ¶
func (*Service) LeaveRemoteSpace ¶
func (*Service) LeaveRemoteVoice ¶
func (*Service) ListAfterRemote ¶
func (s *Service) ListAfterRemote(ctx context.Context, origin string, room *rooms.Room, userID, afterID int64, limit int) ([]messages.Message, map[int64][]messages.ReactionSummary, error)
ListAfterRemote / ListAroundRemote: the other two history cursors (jump-to-message and reading downward out of a jumped-to window), served by the origin like ListRemote.
func (*Service) ListAroundRemote ¶
func (*Service) ListPinsRemote ¶
func (s *Service) ListPinsRemote(ctx context.Context, origin string, room *rooms.Room, userID int64) ([]messages.PinnedMessage, error)
ListPinsRemote reads a hosted channel's pin list from its origin as the local member, and keeps a copy of the messages like history does.
func (*Service) ListRemote ¶
func (*Service) PeerDomains ¶
PeerDomains is every instance this one may talk to: the ones it has met and the ones configured statically, minus anything the allow/block policy refuses.
func (*Service) PinRemote ¶
func (s *Service) PinRemote(ctx context.Context, origin string, room *rooms.Room, userID, msgID int64, remove bool) error
PinRemote asks a channel's origin to pin or unpin as the local member: the origin checks the permission, posts the notice and tells every other mirror; this instance applies the origin's answer to its own copy.
func (*Service) PreviewRemoteInvite ¶
func (*Service) QueryRemote ¶
func (*Service) ReactRemote ¶
func (*Service) RemoteAddMember ¶
func (*Service) RemoteCreateEmoji ¶
func (*Service) RemoteCreateRole ¶
func (*Service) RemoteCreateRoom ¶
func (*Service) RemoteDeleteEmoji ¶
func (*Service) RemoteDeleteInvite ¶
func (*Service) RemoteDeleteRole ¶
func (*Service) RemoteDeleteRoom ¶
func (*Service) RemoteDeleteSpace ¶
func (*Service) RemoteInstallBot ¶
func (*Service) RemoteListAuditLog ¶
func (*Service) RemoteListBans ¶
func (*Service) RemoteListInvites ¶
func (*Service) RemoteModerate ¶
func (*Service) RemoteMoveChannel ¶
func (*Service) RemoteOrigin ¶
func (*Service) RemoteOverride ¶
func (*Service) RemotePatchSpace ¶
func (*Service) RemoteRenameEmoji ¶
func (*Service) RemoteReorderRooms ¶
func (*Service) RemoteSetMemberRoles ¶
func (*Service) RemoteSetSpaceImage ¶
func (*Service) RemoteSpaceOrigin ¶
RemoteSpaceOrigin names the instance hosting a space when it is not this one.
func (*Service) RemoteTransferOwnership ¶
func (*Service) RemoteUpdateRole ¶
func (*Service) RemoteUpdateRoom ¶
func (*Service) RequireInstance ¶
RequireInstance verifies the request signature (see signing.go), the peer policy, the timestamp window and nonce uniqueness, then records the peer domain in Locals.
func (*Service) ResolveHandle ¶
ResolveHandle turns "name@domain" into a local user row: the local user for this instance's own domain (or no domain), or an up-to-date shadow row fetched from the remote instance.
func (*Service) ResolveLocalID ¶
ResolveLocalID maps a federated id to the local row that represents it.
func (*Service) ResyncMirror ¶
func (s *Service) ResyncMirror(ctx context.Context, m *SpaceMapping) error
ResyncMirror reconciles one mirror against its origin's current snapshot. A space the origin no longer has is dropped here too.
func (*Service) ResyncRemote ¶
ResyncRemote is spaces.Federator's resync of one mirror.
func (*Service) RingRemoteCall ¶
func (*Service) RoomFederation ¶
func (*Service) RoomFederations ¶
func (*Service) SearchRemote ¶
func (*Service) SearchSpaceRemote ¶
func (s *Service) SearchSpaceRemote(ctx context.Context, origin string, spaceID, userID int64, opts *messages.SpaceSearchOptions) (*messages.SpaceSearchResult, error)
func (*Service) SendToDeviceRemote ¶
func (*Service) SetDirectory ¶
func (s *Service) SetDirectory(d DirectorySource)
func (*Service) SetSpaces ¶
SetSpaces hands in the API's spaces service (the one with the system-room messenger), so a remote member's join posts the same notice a local join does.
func (*Service) SpaceFederation ¶
func (*Service) StartMaintenance ¶
StartMaintenance makes this process the one that delivers queued relays (outbox.go) and runs ResyncMirror for every mirrored space on a timer until ctx ends.
type Signer ¶
type Signer struct {
KeyID string
Public ed25519.PublicKey
// contains filtered or unexported fields
}
Signer holds this instance's Ed25519 identity.
func LoadExistingSigner ¶
func LoadExistingSigner(cfg config.FederationConfig) (*Signer, error)
LoadExistingSigner is LoadSigner for a process that shares the API's key but must never mint its own (the gateway): a missing key file is an error, not a new identity.
func LoadSigner ¶
func LoadSigner(cfg config.FederationConfig) (*Signer, error)
LoadSigner builds the instance key from FEDERATION_SIGNING_KEY (base64 32-byte seed) or, when unset, from KeyFile - generating and writing a new seed there on first start so the identity is stable across restarts (mount that path on a volume in Docker).
func (*Signer) PublicKeyBase64 ¶
type SoftwareInfo ¶
type SpaceDeleteEvent ¶
type SpaceDeleteEvent struct {
Space SpaceRef `json:"space"`
}
type SpaceEmojiEvent ¶
type SpaceEmojiEvent struct {
Space SpaceRef `json:"space"`
Action string `json:"action"` // upsert | delete
Emoji SpaceEmojiWire `json:"emoji"`
}
SpaceEmojiEvent: POST /spaces/emoji - the origin reports a custom emoji added, renamed or removed. Emoji keep the origin's ids (messages reference them by id).
type SpaceEmojiWire ¶
type SpaceInfo ¶
type SpaceInfo struct {
Name string `json:"name"`
NameAcronym string `json:"name_acronym"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
Banner string `json:"banner,omitempty"`
Owner string `json:"owner"`
VerificationLevel int `json:"verification_level"`
DefaultMessageNotif int `json:"default_message_notifications"`
ExplicitContentFilter int `json:"explicit_content_filter"`
Features []string `json:"features,omitempty"`
AFKRoom string `json:"afk_room,omitempty"`
AFKTimeout int `json:"afk_timeout"`
SystemRoom string `json:"system_room,omitempty"`
SystemRoomFlags int `json:"system_room_flags"`
RulesRoom string `json:"rules_room,omitempty"`
PublicUpdatesRoom string `json:"public_updates_room,omitempty"`
WidgetRoom string `json:"widget_room,omitempty"`
WidgetEnabled bool `json:"widget_enabled"`
MaxPresences int `json:"max_presences"`
MaxMembers int `json:"max_members"`
MaxVideoRoomUsers int `json:"max_video_room_users"`
VanityURLCode string `json:"vanity_url_code,omitempty"`
PreferredLocale string `json:"preferred_locale,omitempty"`
EveryoneRole string `json:"everyone_role"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
SpaceInfo is a space's settings as the origin describes them (room ids are its own).
type SpaceInvitePreviewReply ¶
type SpaceInvitePreviewReply struct {
Space SpaceRef `json:"space"`
Name string `json:"name"`
NameAcronym string `json:"name_acronym"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
Banner string `json:"banner,omitempty"`
MemberCount int `json:"member_count"`
Inviter string `json:"inviter,omitempty"`
}
SpaceInvitePreviewReply: GET /spaces/invites/:code.
type SpaceInviteReply ¶
type SpaceInviteRequest ¶
type SpaceInviteRequest struct {
Space SpaceRef `json:"space"`
User string `json:"user"`
MaxAgeSeconds int `json:"max_age_seconds,omitempty"`
MaxUses int `json:"max_uses,omitempty"`
}
SpaceInviteRequest: POST /spaces/invites - a member on the requesting instance wants an invite for a space hosted here.
type SpaceJoinListedRequest ¶
type SpaceJoinListedRequest struct {
Space SpaceRef `json:"space"`
User Profile `json:"user"`
Presence *auth.PublicPresence `json:"presence,omitempty"`
}
SpaceJoinListedRequest: POST /spaces/join_listed - a peer's user joining a space this instance lists publicly. No invite: the listing is the permission.
type SpaceJoinRequest ¶
type SpaceJoinRequest struct {
Code string `json:"code"`
User Profile `json:"user"`
Presence *auth.PublicPresence `json:"presence,omitempty"`
}
SpaceJoinRequest: POST /spaces/join - a user on the requesting instance redeems an invite for a space hosted here. Presence is how they appear right now, so the member every mirror is told about starts with their real status.
type SpaceManageReply ¶
type SpaceManageReply struct {
Result json.RawMessage `json:"result,omitempty"`
Events []RelayEvent `json:"events"`
}
SpaceManageReply: the op's result (shape per op) and the relays captured for the asking instance.
type SpaceManageRequest ¶
type SpaceManageRequest struct {
Space SpaceRef `json:"space"`
User string `json:"user"` // FID, must belong to the requesting instance
Op string `json:"op"`
Params json.RawMessage `json:"params,omitempty"`
}
SpaceManageRequest: POST /spaces/manage.
type SpaceMapping ¶
type SpaceMapping struct {
SpaceID int64 `db:"space_id"`
OriginDomain string `db:"origin_domain"`
OriginSpaceID int64 `db:"origin_space_id"`
CreatedAt time.Time `db:"created_at"`
}
SpaceMapping ties a local space (a mirror, or a hosted space that has started federating) to its global identity.
type SpaceMemberEvent ¶
type SpaceMemberEvent struct {
Space SpaceRef `json:"space"`
Action string `json:"action"` // add | update | remove
Member SpaceMemberWire `json:"member"`
How string `json:"how,omitempty"` // remove: kicked | banned | left
}
type SpaceMemberWire ¶
type SpaceMemberWire struct {
User Profile `json:"user"`
Roles []string `json:"roles"`
Nickname string `json:"nickname,omitempty"`
JoinedAt time.Time `json:"joined_at"`
// Presence as others see it, so a mirror's member list starts with real statuses
// instead of "offline until their next change".
Presence auth.PublicPresence `json:"presence"`
}
type SpaceMembersQuery ¶
type SpaceMembersQuery struct {
Space SpaceRef `json:"space"`
After string `json:"after,omitempty"`
}
SpaceMembersQuery: POST /spaces/members/list - the page of a hosted space's members after a cursor (a snapshot's members_next, or an earlier page's next).
type SpaceMembersReply ¶
type SpaceMembersReply struct {
Members []SpaceMemberWire `json:"members"`
Next string `json:"next,omitempty"`
}
type SpaceMessageEditRequest ¶
type SpaceMessageEditRequest struct {
Room RoomRef `json:"room"`
Message MessageRef `json:"message"`
User string `json:"user"`
Ciphertext string `json:"ciphertext,omitempty"`
Plaintext string `json:"plaintext,omitempty"`
Emojis []EmojiRef `json:"emojis,omitempty"`
}
SpaceMessageEditRequest: PATCH /spaces/messages.
type SpaceMessageRequest ¶
type SpaceMessageRequest struct {
Room RoomRef `json:"room"`
User string `json:"user"`
SenderDeviceID string `json:"sender_device_id,omitempty"`
Ciphertext string `json:"ciphertext,omitempty"`
Plaintext string `json:"plaintext,omitempty"`
ReplyTo *MessageRef `json:"reply_to,omitempty"`
Mentions []string `json:"mentions,omitempty"`
MentionRoles []string `json:"mention_roles,omitempty"`
MentionEveryone bool `json:"mention_everyone,omitempty"`
Attachments []messages.Attachment `json:"attachments,omitempty"`
// Emojis describes the custom emoji the text uses; mentions in it are <@FID> (content.go).
Emojis []EmojiRef `json:"emojis,omitempty"`
}
SpaceMessageRequest: POST /spaces/messages - a member on the requesting instance sends into a channel hosted here. Attachments were uploaded to their own instance.
type SpaceMessageRequestRef ¶
type SpaceMessageRequestRef struct {
Room RoomRef `json:"room"`
Message MessageRef `json:"message"`
User string `json:"user"`
}
SpaceMessageRequestRef: POST /spaces/messages/delete and /spaces/messages/get.
type SpaceMessagesQuery ¶
type SpaceMessagesQuery struct {
Room RoomRef `json:"room"`
User string `json:"user"`
// At most one of Before / After / Around (origin message ids): the page below a
// message, the page above one (oldest-first), or the window around one - the same
// three cursors GET /rooms/:id/messages takes.
Before string `json:"before,omitempty"`
After string `json:"after,omitempty"`
Around string `json:"around,omitempty"`
Limit int `json:"limit,omitempty"`
}
SpaceMessagesQuery: POST /spaces/messages/list - a page of a channel's history as the asking member may see it.
type SpaceMessagesReply ¶
type SpaceMessagesReply struct {
Messages []MessageEvent `json:"messages"`
}
type SpaceOverrideWire ¶
type SpaceOverrideWire struct {
Role string `json:"role,omitempty"`
User string `json:"user,omitempty"`
Allow int64 `json:"allow"`
Deny int64 `json:"deny"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
SpaceOverrideWire is a room override for a role (Role set) or a user (User set).
type SpacePeer ¶
type SpacePeer struct {
SpaceID int64 `db:"space_id"`
Domain string `db:"domain"`
CreatedAt time.Time `db:"created_at"`
}
SpacePeer is an instance that mirrors a space this instance hosts.
type SpacePeerEvent ¶
type SpacePeerEvent struct {
Space SpaceRef `json:"space"`
Action string `json:"action"` // add | remove
Domain string `json:"domain"`
}
SpacePeerEvent: POST /spaces/peers - an instance started or stopped mirroring the space (origin → mirrors).
type SpaceReactionReply ¶
type SpaceReactionReply struct {
Reactions []messages.ReactionSummary `json:"reactions"`
}
type SpaceRoleEvent ¶
type SpaceRoleEvent struct {
Space SpaceRef `json:"space"`
Action string `json:"action"` // upsert | delete
Role SpaceRoleWire `json:"role"`
}
type SpaceRoleWire ¶
type SpaceRoleWire struct {
ID string `json:"id"`
Name string `json:"name"`
Permissions int64 `json:"permissions"`
Position int `json:"position"`
Color int `json:"color"`
Hoist bool `json:"hoist"`
Mentionable bool `json:"mentionable"`
Bot string `json:"bot,omitempty"` // FID of the bot a managed role belongs to
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type SpaceRoomEvent ¶
type SpaceRoomEvent struct {
Space SpaceRef `json:"space"`
Action string `json:"action"` // upsert | delete | reorder
Room *SpaceRoomWire `json:"room,omitempty"`
Order []SpaceRoomOrder `json:"order,omitempty"`
}
type SpaceRoomOrder ¶
type SpaceRoomWire ¶
type SpaceRoomWire struct {
ID string `json:"id"`
Type int `json:"type"`
Parent string `json:"parent,omitempty"`
Name string `json:"name"`
Topic string `json:"topic,omitempty"`
SlowmodeSeconds int `json:"slowmode_seconds,omitempty"`
Position int `json:"position"`
E2EEEnabled bool `json:"e2ee_enabled"`
UserLimit int `json:"user_limit,omitempty"`
Bitrate int `json:"bitrate,omitempty"`
Overrides []SpaceOverrideWire `json:"overrides,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// Thread is set for a thread room (type 6): its state as the origin holds it. Thread
// membership is not mirrored, so a private thread is not visible on a mirror.
Thread *ThreadWire `json:"thread,omitempty"`
}
type SpaceSearchQuery ¶
type SpaceSearchQuery struct {
Space SpaceRef `json:"space"`
Room *RoomRef `json:"room,omitempty"`
User string `json:"user"`
Query string `json:"query,omitempty"`
From string `json:"from,omitempty"`
Mentions string `json:"mentions,omitempty"`
Has string `json:"has,omitempty"`
Before string `json:"before,omitempty"`
Limit int `json:"limit,omitempty"`
}
SpaceSearchQuery: POST /spaces/messages/search - search a hosted space's text channels (or one of them, Room) as the asking member may read them. From and Mentions are FIDs.
type SpaceSearchReply ¶
type SpaceSearchReply struct {
Messages []MessageEvent `json:"messages"`
NextBefore string `json:"next_before,omitempty"`
RoomsSearched int `json:"rooms_searched"`
EncryptedRooms int `json:"encrypted_rooms"`
}
type SpaceSnapshot ¶
type SpaceSnapshot struct {
Space SpaceRef `json:"space"`
Info SpaceInfo `json:"info"`
Roles []SpaceRoleWire `json:"roles"`
Rooms []SpaceRoomWire `json:"rooms"`
Members []SpaceMemberWire `json:"members"`
MembersNext string `json:"members_next,omitempty"`
Emoji []SpaceEmojiWire `json:"emoji,omitempty"`
MemberCount int `json:"member_count"`
Peers []string `json:"peers,omitempty"`
}
SpaceSnapshot is everything a mirror is built from: the join reply (and a resync). Members is the first page; MembersNext, when set, is the cursor to fetch the rest with /spaces/members/list. Peers are the other instances in the space (the origin itself excluded), so a mirror's users reach them directly with presence and profile changes.
type SpaceSyncRequest ¶
type SpaceSyncRequest struct {
Space SpaceRef `json:"space"`
}
SpaceSyncRequest: POST /spaces/sync - a mirror asks for a fresh snapshot.
type SpaceUpdateEvent ¶
Origin → mirrors.
type SpaceUserRequest ¶
type SpaceUserRequest struct {
Space SpaceRef `json:"space"`
User string `json:"user"` // FID, must belong to the requesting instance
}
SpaceUserRequest: POST /spaces/leave.
type StatusError ¶
StatusError is a non-2xx reply from a peer.
func (*StatusError) Error ¶
func (e *StatusError) Error() string
type ThreadWire ¶
type ThreadWire struct {
Archived bool `json:"archived"`
ArchivedAt *time.Time `json:"archived_at,omitempty"`
AutoArchiveMinutes int `json:"auto_archive_minutes,omitempty"`
Locked bool `json:"locked"`
Private bool `json:"private"`
Invitable bool `json:"invitable"`
LastActiveAt *time.Time `json:"last_active_at,omitempty"`
Owner string `json:"owner,omitempty"` // FID
StarterMessage string `json:"starter_message,omitempty"`
}
ThreadWire is a thread's state on the wire (see rooms.Room's Thread* fields).
type ToDevice ¶
type ToDevice struct {
Sender Profile `json:"sender"`
SenderDeviceID string `json:"sender_device_id"`
EventType string `json:"event_type"`
Messages map[string]map[string]json.RawMessage `json:"messages"`
}
ToDevice: POST /to_device - Olm/Megolm to-device traffic for the receiver's users.
type TypingEvent ¶
TypingEvent: POST /rooms/typing.
type VoiceCall ¶
type VoiceCall struct {
StartedBy string `json:"started_by"`
StartedAt time.Time `json:"started_at"`
Ringing []string `json:"ringing"`
}
VoiceCall is a ringing / running call with its users as FIDs.
type VoiceCallEvent ¶
type VoiceCallEvent struct {
Room RoomRef `json:"room"`
Event string `json:"event"` // CALL_CREATE | CALL_UPDATE | CALL_DELETE
Call *VoiceCall `json:"call,omitempty"`
Starter *Profile `json:"starter,omitempty"`
Rerung bool `json:"rerung,omitempty"`
}
VoiceCallEvent: POST /rooms/voice/call - the origin reports the call starting, changing (ringing set, re-ring) or ending.
type VoiceJoinReply ¶
type VoiceJoinReply struct {
URL string `json:"url"`
Token string `json:"token"`
RoomName string `json:"room_name"`
Bitrate int `json:"bitrate"`
State VoiceState `json:"state"`
States []VoiceState `json:"states"`
Call *VoiceCall `json:"call,omitempty"`
}
VoiceJoinReply is the origin's answer to a join: where to connect, as whom, and who is already there.
type VoiceJoinRequest ¶
type VoiceJoinRequest struct {
Room RoomRef `json:"room"`
User Profile `json:"user"`
SelfMute bool `json:"self_mute"`
SelfDeaf bool `json:"self_deaf"`
}
VoiceJoinRequest: POST /rooms/voice/join - a user on the requesting instance wants a token for the call in a room this instance originated.
type VoiceRing ¶
type VoiceRing struct {
Room RoomRef `json:"room"`
User string `json:"user"`
Targets []string `json:"targets,omitempty"` // FIDs; empty = everyone not yet in
}
VoiceRing: POST /rooms/voice/ring.
type VoiceSelfUpdate ¶
type VoiceSelfUpdate struct {
Room RoomRef `json:"room"`
User string `json:"user"`
SelfMute *bool `json:"self_mute,omitempty"`
SelfDeaf *bool `json:"self_deaf,omitempty"`
SelfVideo *bool `json:"self_video,omitempty"`
SelfStream *bool `json:"self_stream,omitempty"`
}
VoiceSelfUpdate: POST /rooms/voice/self - the user's own flags changed.
type VoiceState ¶
type VoiceState struct {
User Profile `json:"user"`
Identity string `json:"identity"`
SessionID string `json:"session_id"`
SelfMute bool `json:"self_mute"`
SelfDeaf bool `json:"self_deaf"`
Mute bool `json:"mute"`
Deaf bool `json:"deaf"`
SelfVideo bool `json:"self_video"`
SelfStream bool `json:"self_stream"`
Suppress bool `json:"suppress"`
Priority bool `json:"priority_speaker"`
Connected bool `json:"connected"`
JoinedAt time.Time `json:"joined_at"`
}
VoiceState is a voice state as instances describe it to each other: the user as a profile (so a receiver can create the shadow and draw the tile) and the LiveKit identity verbatim, since that is what every client matches participants by.
type VoiceStateEvent ¶
type VoiceStateEvent struct {
Room RoomRef `json:"room"`
State VoiceState `json:"state"`
Left bool `json:"left,omitempty"`
}
VoiceStateEvent: POST /rooms/voice/state - the origin reports one state (changed, or gone when Left).
type VoiceUserRequest ¶
type VoiceUserRequest struct {
Room RoomRef `json:"room"`
User string `json:"user"` // FID, must belong to the requesting instance
}
VoiceUserRequest: POST /rooms/voice/leave and /rooms/voice/decline.