44 lines
1.3 KiB
Go
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))
|
|
}
|