activesync

package
v0.0.0-...-9e684e1 Latest Latest
Warning

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

Go to latest
Published: May 30, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package activesync provides an embeddable Microsoft Exchange ActiveSync server built on Echo v5. Implement the Backend interface and call NewServer to start.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func GeneratePolicyKey

func GeneratePolicyKey() (string, error)

GeneratePolicyKey creates a new random policy key.

func GenerateSyncKey

func GenerateSyncKey() (string, error)

GenerateSyncKey creates a new random sync key.

Types

type Backend

type Backend interface {
	// Logon authenticates the user. Returns false on failure.
	Logon(ctx context.Context, username, domain, password string) bool

	// Logoff is called after the request is complete. Should release resources.
	Logoff(ctx context.Context) error

	// Setup prepares the backend for the given user (and optional impersonated user).
	// This is called after Logon succeeds.
	Setup(ctx context.Context, username, impersonatedUser string) error

	// GetFolderList returns the complete folder hierarchy for the authenticated user.
	GetFolderList(ctx context.Context) ([]protocol.Folder, error)

	// GetFolderSyncKey returns the current sync key for the folder hierarchy.
	// An empty string or "0" means full sync is required.
	GetFolderSyncKey(ctx context.Context) (string, error)

	// SetFolderSyncKey saves a new folder hierarchy sync key.
	SetFolderSyncKey(ctx context.Context, key string) error

	// GetChanges returns items that have changed since the last sync.
	// syncKey "0" means a full sync; a non-zero key returns only deltas.
	// Returns the new sync key and a slice of changes.
	GetChanges(ctx context.Context, folderID, syncKey string, options *SyncOptions) (newKey string, changes []protocol.Change, err error)

	// ApplyChange applies a client-originated change (add/modify/delete) to the backend.
	ApplyChange(ctx context.Context, folderID string, change protocol.Change) (serverID string, err error)

	// GetItemCount returns the estimated number of items to sync for a folder.
	GetItemCount(ctx context.Context, folderID, syncKey string) (int, error)

	// SendMail sends an email message (raw MIME data).
	SendMail(ctx context.Context, mime []byte, saveInSentItems bool) error

	// SmartForward forwards an existing message with additional content.
	SmartForward(ctx context.Context, itemID, folderID string, mime []byte) error

	// SmartReply replies to an existing message.
	SmartReply(ctx context.Context, itemID, folderID string, mime []byte) error

	// GetAttachment fetches an attachment by its file reference.
	GetAttachment(ctx context.Context, fileRef string) (data []byte, contentType string, err error)

	// MoveItems moves one or more items between folders.
	MoveItems(ctx context.Context, moves []protocol.MoveRequest) ([]protocol.MoveResult, error)

	// MeetingResponse processes a meeting accept/decline/tentative response.
	MeetingResponse(ctx context.Context, requestID, folderID string, userResponse protocol.MeetingResponseStatus) (calendarID string, err error)

	// Search performs a search across the mailbox or GAL.
	Search(ctx context.Context, query *SearchQuery) ([]protocol.SearchResult, int, error)

	// GetDevicePolicy returns the device security policy for this user/device.
	// Returning nil means no policy enforcement.
	GetDevicePolicy(ctx context.Context) (*protocol.Policy, error)

	// AcknowledgePolicy acknowledges that the device accepted the policy.
	AcknowledgePolicy(ctx context.Context, policyKey string) error

	// GetDeviceInfo returns stored device info for this device, if any.
	GetDeviceInfo(ctx context.Context, deviceID string) (*protocol.DeviceInfo, error)

	// SaveDeviceInfo stores updated device information from a Settings request.
	SaveDeviceInfo(ctx context.Context, info *protocol.DeviceInfo) error
}

Backend is the interface that backends must implement to provide data to the ActiveSync server. Each method corresponds to one or more AS commands.

A new Backend instance is created per-request via BackendFactory. Logon is always the first call; Logoff is always the last.

type BackendFactory

type BackendFactory func() Backend

BackendFactory creates a new Backend instance for each incoming request.

type DeviceState

type DeviceState struct {
	DeviceID   string
	DeviceType string
	UserAgent  string
	Username   string

	PolicyKey     string
	PolicyAcked   bool
	FolderSyncKey string
	ItemSyncKeys  map[string]string // folderID → syncKey
	LastSyncTime  map[string]time.Time

	CreatedAt time.Time
	UpdatedAt time.Time
	// contains filtered or unexported fields
}

DeviceState holds per-device synchronization state. In production, persist this via a StateMachine implementation.

func NewDeviceState

func NewDeviceState(deviceID, deviceType, username string) *DeviceState

NewDeviceState creates an empty DeviceState for the given device.

func (*DeviceState) GetSyncKey

func (d *DeviceState) GetSyncKey(folderID string) string

GetSyncKey returns the current sync key for a folder. Returns "0" if no key has been assigned yet.

func (*DeviceState) SetSyncKey

func (d *DeviceState) SetSyncKey(folderID, key string)

SetSyncKey updates the sync key for a folder.

type DeviceStore

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

DeviceStore is a thread-safe in-memory store for DeviceState objects. Replace with a persistent implementation for production use.

func NewDeviceStore

func NewDeviceStore() *DeviceStore

NewDeviceStore creates an empty in-memory device store.

func (*DeviceStore) Get

func (s *DeviceStore) Get(deviceID, deviceType, username string) *DeviceState

Get retrieves or creates a DeviceState for the given device/user pair.

func (*DeviceStore) Save

func (s *DeviceStore) Save(d *DeviceState) error

Save persists an updated DeviceState (no-op in the in-memory implementation).

type Dispatcher

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

Dispatcher routes ActiveSync POST requests to the correct handler.

func NewDispatcher

func NewDispatcher(h *Handler) *Dispatcher

NewDispatcher creates a Dispatcher from a Handler.

func (*Dispatcher) HandleActiveSyncPost

func (d *Dispatcher) HandleActiveSyncPost(c *echo.Context) error

HandleActiveSyncPost is the main Echo handler for POST /Microsoft-Server-ActiveSync.

func (*Dispatcher) HandleOptions

func (d *Dispatcher) HandleOptions(c *echo.Context) error

HandleOptions handles HTTP OPTIONS requests (capability discovery).

type Handler

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

Handler holds shared dependencies for all AS command handlers. It lives inside pkg/activesync so it can reference Backend, DeviceStore, Options directly.

func NewHandler

func NewHandler(factory BackendFactory, deviceStore *DeviceStore, opts *Options, logger *zap.Logger) *Handler

NewHandler creates a Handler instance.

func (*Handler) HandleAutodiscover

func (h *Handler) HandleAutodiscover(c *echo.Context) error

HandleAutodiscover responds to Exchange Autodiscover requests. It returns the server URL for ActiveSync configuration.

func (*Handler) HandleFolderSync

func (h *Handler) HandleFolderSync(c *echo.Context, backend Backend, deviceState *DeviceState) error

HandleFolderSync processes a FolderSync command. The client sends its current folder sync key; the server returns any changes to the folder hierarchy since that key.

func (*Handler) HandleGetItemEstimate

func (h *Handler) HandleGetItemEstimate(c *echo.Context, backend Backend, _ *DeviceState) error

HandleGetItemEstimate processes a GetItemEstimate command. Returns the estimated number of items to sync for each requested collection.

func (*Handler) HandleMeetingResponse

func (h *Handler) HandleMeetingResponse(c *echo.Context, backend Backend, _ *DeviceState) error

HandleMeetingResponse processes a MeetingResponse command.

func (*Handler) HandleMoveItems

func (h *Handler) HandleMoveItems(c *echo.Context, backend Backend, _ *DeviceState) error

HandleMoveItems processes a MoveItems command.

func (*Handler) HandlePing

func (h *Handler) HandlePing(c *echo.Context, backend Backend, _ *DeviceState) error

HandlePing processes a Ping command (long-poll for server-side changes). The server holds the connection open until changes arrive or the heartbeat interval expires.

func (*Handler) HandleProvision

func (h *Handler) HandleProvision(c *echo.Context, backend Backend, deviceState *DeviceState) error

HandleProvision processes a Provision command. Phase 1: client requests policy → server sends policy + temp key. Phase 2: client acknowledges policy → server sends permanent key.

func (*Handler) HandleSearch

func (h *Handler) HandleSearch(c *echo.Context, backend Backend, _ *DeviceState) error

HandleSearch processes a Search command.

func (*Handler) HandleSendMail

func (h *Handler) HandleSendMail(c *echo.Context, backend Backend, _ *DeviceState) error

HandleSendMail processes a SendMail command. The request body contains raw MIME data (not WBXML).

func (*Handler) HandleSettings

func (h *Handler) HandleSettings(c *echo.Context, backend Backend, deviceState *DeviceState) error

HandleSettings processes a Settings command.

func (*Handler) HandleSmartForward

func (h *Handler) HandleSmartForward(c *echo.Context, backend Backend, _ *DeviceState) error

HandleSmartForward processes a SmartForward command.

func (*Handler) HandleSmartReply

func (h *Handler) HandleSmartReply(c *echo.Context, backend Backend, _ *DeviceState) error

HandleSmartReply processes a SmartReply command.

func (*Handler) HandleSync

func (h *Handler) HandleSync(c *echo.Context, backend Backend, deviceState *DeviceState) error

HandleSync processes a Sync command. The client sends collection sync keys; the server returns changes.

type Options

type Options struct {
	// Addr is the listen address, e.g. ":8080" or ":443".
	Addr string

	// TLSCert and TLSKey are paths to the TLS certificate and key files.
	// If empty, the server starts without TLS (not suitable for production).
	TLSCert string
	TLSKey  string

	// Logger is the zap logger. If nil, a production logger is created.
	Logger *zap.Logger

	// MaxPingInterval is the maximum heartbeat interval for Ping commands (seconds).
	// Default: 540 (9 minutes).
	MaxPingInterval int

	// MinPingInterval is the minimum heartbeat interval (seconds).
	// Default: 60.
	MinPingInterval int

	// MaxPingFolders is the maximum number of folders a Ping command may monitor.
	// Default: 100.
	MaxPingFolders int

	// EnforceProvisioning requires clients to exchange a policy before syncing.
	// Default: false (permissive for testing).
	EnforceProvisioning bool

	// ServerHeader overrides the X-MS-Server-ActiveSync header value.
	ServerHeader string
}

Options configures the ActiveSync server.

type SearchQuery

type SearchQuery struct {
	StoreName     string
	Query         string
	FreeText      string
	RangeStart    int
	RangeEnd      int
	DeepTraversal bool
}

SearchQuery encapsulates a Search command request.

type Server

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

Server is the ActiveSync server. It wraps an Echo instance and routes all AS protocol requests through the registered Backend.

func NewServer

func NewServer(opts Options) *Server

NewServer creates a new ActiveSync server with the given options. Call SetBackendFactory before Start.

func (*Server) Echo

func (s *Server) Echo() *echo.Echo

Echo returns the underlying Echo instance for advanced customization.

func (*Server) SetBackendFactory

func (s *Server) SetBackendFactory(f BackendFactory)

SetBackendFactory registers the factory that creates a Backend per request.

func (*Server) Start

func (s *Server) Start(ctx context.Context) error

Start starts the HTTP server. Blocks until ctx is cancelled or an error occurs.

type SyncOptions

type SyncOptions struct {
	FilterType     protocol.FilterType
	WindowSize     int
	BodyType       protocol.BodyType
	TruncationSize int
	MIMESupport    int
}

SyncOptions holds per-collection sync options from the client.

Jump to

Keyboard shortcuts

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