Files

44 lines
1.3 KiB
Go

package xmpp
import (
"encoding/base64"
"fmt"
"regexp"
"strings"
)
var authcidRe = regexp.MustCompile(`^[A-Za-z0-9]{1,64}$`)
// SASLAuth parses a PLAIN mechanism auth element value.
type SASLAuth struct {
Authzid string
Authcid string // robot serial from the base64 credential
Password string
}
// ParseSASLPlain decodes a base64 PLAIN token. It accepts an empty password but
// rejects missing fields or an invalid authcid.
func ParseSASLPlain(token string) (SASLAuth, error) {
decoded, err := base64.StdEncoding.DecodeString(token)
if err != nil {
return SASLAuth{}, fmt.Errorf("base64: %w", err)
}
parts := strings.Split(string(decoded), "\x00")
if len(parts) != 3 {
return SASLAuth{}, fmt.Errorf("expected 3 NUL-separated fields, got %d", len(parts))
}
auth := SASLAuth{Authzid: parts[0], Authcid: parts[1], Password: parts[2]}
if auth.Authcid == "" || !authcidRe.MatchString(auth.Authcid) {
return SASLAuth{}, fmt.Errorf("invalid authcid")
}
return auth, nil
}
// SASLSuccessXML is the SASL success stanza.
var SASLSuccessXML = []byte(`<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>`)
// SASLFailureXML returns a failure stanza for the named condition.
func SASLFailureXML(condition string) []byte {
return []byte(fmt.Sprintf(`<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><%s/></failure>`, condition))
}