upgrade deps; rewrite smtp session

This commit is contained in:
Aine
2024-02-19 22:55:14 +02:00
parent 10213cc7d7
commit a01720da00
277 changed files with 106832 additions and 7641 deletions

View File

@@ -1,11 +1,12 @@
# go-sasl
[![GoDoc](https://godoc.org/github.com/emersion/go-sasl?status.svg)](https://godoc.org/github.com/emersion/go-sasl)
[![godocs.io](https://godocs.io/github.com/emersion/go-sasl?status.svg)](https://godocs.io/github.com/emersion/go-sasl)
[![Build Status](https://travis-ci.org/emersion/go-sasl.svg?branch=master)](https://travis-ci.org/emersion/go-sasl)
A [SASL](https://tools.ietf.org/html/rfc4422) library written in Go.
Implemented mechanisms:
* [ANONYMOUS](https://tools.ietf.org/html/rfc4505)
* [EXTERNAL](https://tools.ietf.org/html/rfc4422#appendix-A)
* [LOGIN](https://tools.ietf.org/html/draft-murchison-sasl-login-00) (obsolete, use PLAIN instead)

View File

@@ -27,7 +27,7 @@ func NewAnonymousClient(trace string) Client {
type AnonymousAuthenticator func(trace string) error
type anonymousServer struct {
done bool
done bool
authenticate AnonymousAuthenticator
}

View File

@@ -1,5 +1,10 @@
package sasl
import (
"bytes"
"errors"
)
// The EXTERNAL mechanism name.
const External = "EXTERNAL"
@@ -24,3 +29,39 @@ func (a *externalClient) Next(challenge []byte) (response []byte, err error) {
func NewExternalClient(identity string) Client {
return &externalClient{identity}
}
// ExternalAuthenticator authenticates users with the EXTERNAL mechanism. If
// the identity is left blank, it indicates that it is the same as the one used
// in the external credentials. If identity is not empty and the server doesn't
// support it, an error must be returned.
type ExternalAuthenticator func(identity string) error
type externalServer struct {
done bool
authenticate ExternalAuthenticator
}
func (a *externalServer) Next(response []byte) (challenge []byte, done bool, err error) {
if a.done {
return nil, false, ErrUnexpectedClientResponse
}
// No initial response, send an empty challenge
if response == nil {
return []byte{}, false, nil
}
a.done = true
if bytes.Contains(response, []byte("\x00")) {
return nil, false, errors.New("sasl: identity contains a NUL character")
}
return nil, true, a.authenticate(string(response))
}
// NewExternalServer creates a server implementation of the EXTERNAL
// authentication mechanism, as described in RFC 4422.
func NewExternalServer(authenticator ExternalAuthenticator) Server {
return &externalServer{authenticate: authenticator}
}

View File

@@ -35,8 +35,11 @@ type oauthBearerClient struct {
}
func (a *oauthBearerClient) Start() (mech string, ir []byte, err error) {
mech = OAuthBearer
var str = "n,a=" + a.Username + ","
var authzid string
if a.Username != "" {
authzid = "a=" + a.Username
}
str := "n," + authzid + ","
if a.Host != "" {
str += "\x01host=" + a.Host
@@ -47,7 +50,7 @@ func (a *oauthBearerClient) Start() (mech string, ir []byte, err error) {
}
str += "\x01auth=Bearer " + a.Token + "\x01\x01"
ir = []byte(str)
return
return OAuthBearer, ir, nil
}
func (a *oauthBearerClient) Next(challenge []byte) ([]byte, error) {
@@ -81,7 +84,7 @@ func (a *oauthBearerServer) fail(descr string) ([]byte, bool, error) {
if err != nil {
panic(err) // wtf
}
a.failErr = errors.New(descr)
a.failErr = errors.New("sasl: client error: " + descr)
return blob, false, nil
}
@@ -95,7 +98,7 @@ func (a *oauthBearerServer) Next(response []byte) (challenge []byte, done bool,
// indirectly OAUTHBEARER) defines a protocol-independent way to do so
// using 0x01.
if len(response) != 1 && response[0] != 0x01 {
return nil, true, errors.New("unexpected response")
return nil, true, errors.New("sasl: invalid response")
}
return nil, true, a.failErr
}
@@ -121,14 +124,18 @@ func (a *oauthBearerServer) Next(response []byte) (challenge []byte, done bool,
if len(parts) != 3 {
return a.fail("Invalid response")
}
if !bytes.Equal(parts[0], []byte{'n'}) {
return a.fail("Invalid response, missing 'n'")
flag := parts[0]
authzid := parts[1]
if !bytes.Equal(flag, []byte{'n'}) {
return a.fail("Invalid response, missing 'n' in gs2-cb-flag")
}
opts := OAuthBearerOptions{}
if !bytes.HasPrefix(parts[1], []byte("a=")) {
return a.fail("Invalid response, missing 'a'")
if len(authzid) > 0 {
if !bytes.HasPrefix(authzid, []byte("a=")) {
return a.fail("Invalid response, missing 'a=' in gs2-authzid")
}
opts.Username = string(bytes.TrimPrefix(authzid, []byte("a=")))
}
opts.Username = string(bytes.TrimPrefix(parts[1], []byte("a=")))
// Cut \x01host=...\x01auth=...\x01\x01
// into

View File

@@ -38,7 +38,7 @@ func NewPlainClient(identity, username, password string) Client {
type PlainAuthenticator func(identity, username, password string) error
type plainServer struct {
done bool
done bool
authenticate PlainAuthenticator
}
@@ -57,7 +57,7 @@ func (a *plainServer) Next(response []byte) (challenge []byte, done bool, err er
parts := bytes.Split(response, []byte("\x00"))
if len(parts) != 3 {
err = errors.New("Invalid response")
err = errors.New("sasl: invalid response")
return
}

View File

@@ -12,7 +12,7 @@ import (
// Common SASL errors.
var (
ErrUnexpectedClientResponse = errors.New("sasl: unexpected client response")
ErrUnexpectedClientResponse = errors.New("sasl: unexpected client response")
ErrUnexpectedServerChallenge = errors.New("sasl: unexpected server challenge")
)