feat: implement XEP-0077 In-Band Registration support

- Add XEPFeatures framework for managing XMPP extension protocols
- Implement complete XEP-0077 In-Band Registration functionality
- Add server capability detection using disco#info queries
- Only initialize XEP features when server supports them
- Add comprehensive XEP-0077 testing to doctor command
- Doctor tests create and delete test users to validate functionality
- Add struct-based XEP management instead of dynamic maps

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Felipe M 2025-08-06 19:16:37 +02:00
parent 53818ade7f
commit a76200f4b9
No known key found for this signature in database
GPG key ID: 52E5D65FCF99808A
4 changed files with 627 additions and 0 deletions

View file

@ -57,6 +57,9 @@ type Client struct {
// Message deduplication cache to handle XMPP server duplicates
dedupeCache *ttlcache.Cache[string, time.Time]
// XEP features manager for handling XMPP extension protocols
XEPFeatures *XEPFeatures
}
// MessageRequest represents a request to send a message.
@ -132,6 +135,7 @@ func NewClient(serverURL, username, password, resource, remoteID string, log log
cancel: cancel,
sessionReady: make(chan struct{}),
dedupeCache: dedupeCache,
XEPFeatures: NewXEPFeatures(log),
}
// Create MUC client and set up message handling
@ -169,6 +173,70 @@ func (c *Client) GetJID() jid.JID {
return c.jidAddr
}
// GetInBandRegistration returns the InBandRegistration XEP handler for registration operations
func (c *Client) GetInBandRegistration() (*InBandRegistration, error) {
if c.XEPFeatures.InBandRegistration == nil {
return nil, fmt.Errorf("InBandRegistration XEP not available")
}
return c.XEPFeatures.InBandRegistration, nil
}
// detectServerCapabilities discovers which XEPs are supported by the server
func (c *Client) detectServerCapabilities() {
if c.session == nil {
c.logger.LogError("Cannot detect server capabilities: no session")
return
}
c.logger.LogDebug("Detecting server capabilities for XEP support")
// Check for XEP-0077 In-Band Registration support
if c.checkInBandRegistrationSupport() {
// Only create and initialize the InBandRegistration XEP if server supports it
inBandReg := NewInBandRegistration(c, c.logger)
c.XEPFeatures.InBandRegistration = inBandReg
c.logger.LogInfo("Initialized XEP-0077 In-Band Registration support")
} else {
c.logger.LogDebug("Server does not support XEP-0077 In-Band Registration - feature not initialized")
}
enabledFeatures := c.XEPFeatures.ListFeatures()
c.logger.LogInfo("Server capability detection completed", "enabled_xeps", enabledFeatures)
}
// checkInBandRegistrationSupport checks if the server supports XEP-0077 In-Band Registration
func (c *Client) checkInBandRegistrationSupport() bool {
if c.session == nil {
return false
}
// Create context with timeout
ctx, cancel := context.WithTimeout(c.ctx, 10*time.Second)
defer cancel()
c.logger.LogDebug("Checking server support for XEP-0077 In-Band Registration")
// Use disco#info to query the server for registration support
serverDomain := c.jidAddr.Domain()
info, err := disco.GetInfo(ctx, "", serverDomain, c.session)
if err != nil {
c.logger.LogDebug("Failed to get server disco info for registration check", "error", err)
return false
}
// Check for the registration feature in server features
for _, feature := range info.Features {
if feature.Var == NSRegister {
c.logger.LogDebug("Server supports XEP-0077 In-Band Registration", "feature", feature.Var)
return true
}
}
c.logger.LogDebug("Server does not advertise XEP-0077 In-Band Registration support")
return false
}
// parseServerAddress parses a server URL and returns a host:port address
func (c *Client) parseServerAddress(serverURL string) (string, error) {
// Handle simple host:port format (e.g., "localhost:5222")
@ -287,6 +355,10 @@ func (c *Client) Connect() error {
return fmt.Errorf("failed to start session serving")
}
c.logger.LogInfo("XMPP client connected successfully", "jid", c.jidAddr.String())
// Detect server capabilities and enable supported XEPs
go c.detectServerCapabilities()
return nil
case <-time.After(10 * time.Second):
return fmt.Errorf("timeout waiting for session to be ready")