updated deps; updated healthchecks.io integration
This commit is contained in:
30
vendor/github.com/emersion/go-smtp/backend.go
generated
vendored
30
vendor/github.com/emersion/go-smtp/backend.go
generated
vendored
@@ -2,6 +2,8 @@ package smtp
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/emersion/go-sasl"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,6 +22,11 @@ var (
|
||||
EnhancedCode: EnhancedCode{5, 7, 0},
|
||||
Message: "Authentication not supported",
|
||||
}
|
||||
ErrAuthUnknownMechanism = &SMTPError{
|
||||
Code: 504,
|
||||
EnhancedCode: EnhancedCode{5, 7, 4},
|
||||
Message: "Unsupported authentication mechanism",
|
||||
}
|
||||
)
|
||||
|
||||
// A SMTP server backend.
|
||||
@@ -27,6 +34,17 @@ type Backend interface {
|
||||
NewSession(c *Conn) (Session, error)
|
||||
}
|
||||
|
||||
// BackendFunc is an adapter to allow the use of an ordinary function as a
|
||||
// Backend.
|
||||
type BackendFunc func(c *Conn) (Session, error)
|
||||
|
||||
var _ Backend = (BackendFunc)(nil)
|
||||
|
||||
// NewSession calls f(c).
|
||||
func (f BackendFunc) NewSession(c *Conn) (Session, error) {
|
||||
return f(c)
|
||||
}
|
||||
|
||||
// Session is used by servers to respond to an SMTP client.
|
||||
//
|
||||
// The methods are called when the remote client issues the matching command.
|
||||
@@ -37,9 +55,6 @@ type Session interface {
|
||||
// Free all resources associated with session.
|
||||
Logout() error
|
||||
|
||||
// Authenticate the user using SASL PLAIN.
|
||||
AuthPlain(username, password string) error
|
||||
|
||||
// Set return path for currently processed message.
|
||||
Mail(from string, opts *MailOptions) error
|
||||
// Add recipient for currently processed message.
|
||||
@@ -76,3 +91,12 @@ type LMTPSession interface {
|
||||
type StatusCollector interface {
|
||||
SetStatus(rcptTo string, err error)
|
||||
}
|
||||
|
||||
// AuthSession is an add-on interface for Session. It provides support for the
|
||||
// AUTH extension.
|
||||
type AuthSession interface {
|
||||
Session
|
||||
|
||||
AuthMechanisms() []string
|
||||
Auth(mech string) (sasl.Server, error)
|
||||
}
|
||||
|
||||
213
vendor/github.com/emersion/go-smtp/client.go
generated
vendored
213
vendor/github.com/emersion/go-smtp/client.go
generated
vendored
@@ -27,14 +27,11 @@ type Client struct {
|
||||
text *textproto.Conn
|
||||
serverName string
|
||||
lmtp bool
|
||||
// map of supported extensions
|
||||
ext map[string]string
|
||||
// supported auth mechanisms
|
||||
auth []string
|
||||
localName string // the name to use in HELO/EHLO/LHLO
|
||||
didHello bool // whether we've said HELO/EHLO/LHLO
|
||||
helloError error // the error from the hello
|
||||
rcpts []string // recipients accumulated for the current session
|
||||
ext map[string]string // supported extensions
|
||||
localName string // the name to use in HELO/EHLO/LHLO
|
||||
didHello bool // whether we've said HELO/EHLO/LHLO
|
||||
helloError error // the error from the hello
|
||||
rcpts []string // recipients accumulated for the current session
|
||||
|
||||
// Time to wait for command responses (this includes 3xx reply to DATA).
|
||||
CommandTimeout time.Duration
|
||||
@@ -54,7 +51,8 @@ var defaultDialer = net.Dialer{Timeout: defaultTimeout}
|
||||
// Dial returns a new Client connected to an SMTP server at addr. The addr must
|
||||
// include a port, as in "mail.example.com:smtp".
|
||||
//
|
||||
// This function returns a plaintext connection. To enable TLS, use StartTLS.
|
||||
// This function returns a plaintext connection. To enable TLS, use
|
||||
// DialStartTLS.
|
||||
func Dial(addr string) (*Client, error) {
|
||||
conn, err := defaultDialer.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
@@ -83,6 +81,22 @@ func DialTLS(addr string, tlsConfig *tls.Config) (*Client, error) {
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// DialStartTLS retruns a new Client connected to an SMTP server via STARTTLS
|
||||
// at addr. The addr must include a port, as in "mail.example.com:smtp".
|
||||
//
|
||||
// A nil tlsConfig is equivalent to a zero tls.Config.
|
||||
func DialStartTLS(addr string, tlsConfig *tls.Config) (*Client, error) {
|
||||
c, err := Dial(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := initStartTLS(c, tlsConfig); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewClient returns a new Client using an existing connection and host as a
|
||||
// server name to be used when authenticating.
|
||||
func NewClient(conn net.Conn) *Client {
|
||||
@@ -102,6 +116,29 @@ func NewClient(conn net.Conn) *Client {
|
||||
return c
|
||||
}
|
||||
|
||||
// NewClientStartTLS creates a new Client and performs a STARTTLS command.
|
||||
func NewClientStartTLS(conn net.Conn, tlsConfig *tls.Config) (*Client, error) {
|
||||
c := NewClient(conn)
|
||||
if err := initStartTLS(c, tlsConfig); err != nil {
|
||||
c.Close()
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func initStartTLS(c *Client, tlsConfig *tls.Config) error {
|
||||
if err := c.hello(); err != nil {
|
||||
return err
|
||||
}
|
||||
if ok, _ := c.Extension("STARTTLS"); !ok {
|
||||
return errors.New("smtp: server doesn't support STARTTLS")
|
||||
}
|
||||
if err := c.startTLS(tlsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewClientLMTP returns a new LMTP Client (as defined in RFC 2033) using an
|
||||
// existing connection and host as a server name to be used when authenticating.
|
||||
func NewClientLMTP(conn net.Conn) *Client {
|
||||
@@ -247,20 +284,17 @@ func (c *Client) ehlo() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
if mechs, ok := ext["AUTH"]; ok {
|
||||
c.auth = strings.Split(mechs, " ")
|
||||
}
|
||||
c.ext = ext
|
||||
return err
|
||||
}
|
||||
|
||||
// StartTLS sends the STARTTLS command and encrypts all further communication.
|
||||
// startTLS sends the STARTTLS command and encrypts all further communication.
|
||||
// Only servers that advertise the STARTTLS extension support this function.
|
||||
//
|
||||
// A nil config is equivalent to a zero tls.Config.
|
||||
//
|
||||
// If server returns an error, it will be of type *SMTPError.
|
||||
func (c *Client) StartTLS(config *tls.Config) error {
|
||||
func (c *Client) startTLS(config *tls.Config) error {
|
||||
if err := c.hello(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -284,7 +318,7 @@ func (c *Client) StartTLS(config *tls.Config) error {
|
||||
}
|
||||
|
||||
// TLSConnectionState returns the client's TLS connection state.
|
||||
// The return values are their zero values if StartTLS did
|
||||
// The return values are their zero values if STARTTLS did
|
||||
// not succeed.
|
||||
func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool) {
|
||||
tc, ok := c.conn.(*tls.Conn)
|
||||
@@ -572,7 +606,7 @@ func (c *Client) LMTPData(statusCb func(rcpt string, status *SMTPError)) (io.Wri
|
||||
// address from, to addresses to, with message r.
|
||||
//
|
||||
// This function does not start TLS, nor does it perform authentication. Use
|
||||
// StartTLS and Auth before-hand if desirable.
|
||||
// DialStartTLS and Auth before-hand if desirable.
|
||||
//
|
||||
// The addresses in the to parameter are the SMTP RCPT addresses.
|
||||
//
|
||||
@@ -606,6 +640,46 @@ func (c *Client) SendMail(from string, to []string, r io.Reader) error {
|
||||
|
||||
var testHookStartTLS func(*tls.Config) // nil, except for tests
|
||||
|
||||
func sendMail(addr string, implicitTLS bool, a sasl.Client, from string, to []string, r io.Reader) error {
|
||||
if err := validateLine(from); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, recp := range to {
|
||||
if err := validateLine(recp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
c *Client
|
||||
err error
|
||||
)
|
||||
if implicitTLS {
|
||||
c, err = DialTLS(addr, nil)
|
||||
} else {
|
||||
c, err = DialStartTLS(addr, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if a != nil {
|
||||
if ok, _ := c.Extension("AUTH"); !ok {
|
||||
return errors.New("smtp: server doesn't support AUTH")
|
||||
}
|
||||
if err = c.Auth(a); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.SendMail(from, to, r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return c.Quit()
|
||||
}
|
||||
|
||||
// SendMail connects to the server at addr, switches to TLS, authenticates with
|
||||
// the optional SASL client, and then sends an email from address from, to
|
||||
// addresses to, with message r. The addr must include a port, as in
|
||||
@@ -628,76 +702,12 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests
|
||||
// attachments (see the mime/multipart package or the go-message package), or
|
||||
// other mail functionality.
|
||||
func SendMail(addr string, a sasl.Client, from string, to []string, r io.Reader) error {
|
||||
if err := validateLine(from); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, recp := range to {
|
||||
if err := validateLine(recp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c, err := Dial(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if err = c.hello(); err != nil {
|
||||
return err
|
||||
}
|
||||
if ok, _ := c.Extension("STARTTLS"); !ok {
|
||||
return errors.New("smtp: server doesn't support STARTTLS")
|
||||
}
|
||||
if err = c.StartTLS(nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if a != nil {
|
||||
if ok, _ := c.Extension("AUTH"); !ok {
|
||||
return errors.New("smtp: server doesn't support AUTH")
|
||||
}
|
||||
if err = c.Auth(a); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.SendMail(from, to, r); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Quit()
|
||||
return sendMail(addr, false, a, from, to, r)
|
||||
}
|
||||
|
||||
// SendMailTLS works like SendMail, but with implicit TLS.
|
||||
func SendMailTLS(addr string, a sasl.Client, from string, to []string, r io.Reader) error {
|
||||
if err := validateLine(from); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, recp := range to {
|
||||
if err := validateLine(recp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
c, err := DialTLS(addr, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
if err = c.hello(); err != nil {
|
||||
return err
|
||||
}
|
||||
if a != nil {
|
||||
if ok, _ := c.Extension("AUTH"); !ok {
|
||||
return errors.New("smtp: server doesn't support AUTH")
|
||||
}
|
||||
if err = c.Auth(a); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.SendMail(from, to, r); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Quit()
|
||||
return sendMail(addr, true, a, from, to, r)
|
||||
}
|
||||
|
||||
// Extension reports whether an extension is support by the server.
|
||||
@@ -708,14 +718,47 @@ func (c *Client) Extension(ext string) (bool, string) {
|
||||
if err := c.hello(); err != nil {
|
||||
return false, ""
|
||||
}
|
||||
if c.ext == nil {
|
||||
return false, ""
|
||||
}
|
||||
ext = strings.ToUpper(ext)
|
||||
param, ok := c.ext[ext]
|
||||
return ok, param
|
||||
}
|
||||
|
||||
// SupportsAuth checks whether an authentication mechanism is supported.
|
||||
func (c *Client) SupportsAuth(mech string) bool {
|
||||
if err := c.hello(); err != nil {
|
||||
return false
|
||||
}
|
||||
mechs, ok := c.ext["AUTH"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
for _, m := range strings.Split(mechs, " ") {
|
||||
if strings.EqualFold(m, mech) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// MaxMessageSize returns the maximum message size accepted by the server.
|
||||
// 0 means unlimited.
|
||||
//
|
||||
// If the server doesn't convey this information, ok = false is returned.
|
||||
func (c *Client) MaxMessageSize() (size int, ok bool) {
|
||||
if err := c.hello(); err != nil {
|
||||
return 0, false
|
||||
}
|
||||
v := c.ext["SIZE"]
|
||||
if v == "" {
|
||||
return 0, false
|
||||
}
|
||||
size, err := strconv.Atoi(v)
|
||||
if err != nil || size < 0 {
|
||||
return 0, false
|
||||
}
|
||||
return size, true
|
||||
}
|
||||
|
||||
// Reset sends the RSET command to the server, aborting the current mail
|
||||
// transaction.
|
||||
func (c *Client) Reset() error {
|
||||
|
||||
68
vendor/github.com/emersion/go-smtp/conn.go
generated
vendored
68
vendor/github.com/emersion/go-smtp/conn.go
generated
vendored
@@ -15,6 +15,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/emersion/go-sasl"
|
||||
)
|
||||
|
||||
// Number of errors we'll tolerate per connection before closing. Defaults to 3.
|
||||
@@ -139,11 +141,7 @@ func (c *Conn) handle(cmd string, arg string) {
|
||||
c.writeResponse(221, EnhancedCode{2, 0, 0}, "Bye")
|
||||
c.Close()
|
||||
case "AUTH":
|
||||
if c.server.AuthDisabled {
|
||||
c.protocolError(500, EnhancedCode{5, 5, 2}, "Syntax error, AUTH command unrecognized")
|
||||
} else {
|
||||
c.handleAuth(arg)
|
||||
}
|
||||
c.handleAuth(arg)
|
||||
case "STARTTLS":
|
||||
c.handleStartTLS()
|
||||
default:
|
||||
@@ -205,7 +203,7 @@ func (c *Conn) Conn() net.Conn {
|
||||
|
||||
func (c *Conn) authAllowed() bool {
|
||||
_, isTLS := c.TLSConnectionState()
|
||||
return !c.server.AuthDisabled && (isTLS || c.server.AllowInsecureAuth)
|
||||
return isTLS || c.server.AllowInsecureAuth
|
||||
}
|
||||
|
||||
// protocolError writes errors responses and closes the connection once too many
|
||||
@@ -250,18 +248,26 @@ func (c *Conn) handleGreet(enhanced bool, arg string) {
|
||||
return
|
||||
}
|
||||
|
||||
caps := []string{}
|
||||
caps = append(caps, c.server.caps...)
|
||||
caps := []string{
|
||||
"PIPELINING",
|
||||
"8BITMIME",
|
||||
"ENHANCEDSTATUSCODES",
|
||||
"CHUNKING",
|
||||
}
|
||||
if _, isTLS := c.TLSConnectionState(); c.server.TLSConfig != nil && !isTLS {
|
||||
caps = append(caps, "STARTTLS")
|
||||
}
|
||||
if c.authAllowed() {
|
||||
mechs := c.authMechanisms()
|
||||
|
||||
authCap := "AUTH"
|
||||
for name := range c.server.auths {
|
||||
for _, name := range mechs {
|
||||
authCap += " " + name
|
||||
}
|
||||
|
||||
caps = append(caps, authCap)
|
||||
if len(mechs) > 0 {
|
||||
caps = append(caps, authCap)
|
||||
}
|
||||
}
|
||||
if c.server.EnableSMTPUTF8 {
|
||||
caps = append(caps, "SMTPUTF8")
|
||||
@@ -280,6 +286,9 @@ func (c *Conn) handleGreet(enhanced bool, arg string) {
|
||||
} else {
|
||||
caps = append(caps, "SIZE")
|
||||
}
|
||||
if c.server.MaxRecipients > 0 {
|
||||
caps = append(caps, fmt.Sprintf("LIMITS RCPTMAX=%v", c.server.MaxRecipients))
|
||||
}
|
||||
|
||||
args := []string{"Hello " + domain}
|
||||
args = append(args, caps...)
|
||||
@@ -348,16 +357,18 @@ func (c *Conn) handleMail(arg string) {
|
||||
}
|
||||
opts.RequireTLS = true
|
||||
case "BODY":
|
||||
switch value {
|
||||
case "BINARYMIME":
|
||||
value = strings.ToUpper(value)
|
||||
switch BodyType(value) {
|
||||
case BodyBinaryMIME:
|
||||
if !c.server.EnableBINARYMIME {
|
||||
c.writeResponse(504, EnhancedCode{5, 5, 4}, "BINARYMIME is not implemented")
|
||||
return
|
||||
}
|
||||
c.binarymime = true
|
||||
case "7BIT", "8BITMIME":
|
||||
case Body7Bit, Body8BitMIME:
|
||||
// This space is intentionally left blank
|
||||
default:
|
||||
c.writeResponse(500, EnhancedCode{5, 5, 4}, "Unknown BODY value")
|
||||
c.writeResponse(501, EnhancedCode{5, 5, 4}, "Unknown BODY value")
|
||||
return
|
||||
}
|
||||
opts.Body = BodyType(value)
|
||||
@@ -765,7 +776,7 @@ func (c *Conn) handleAuth(arg string) {
|
||||
return
|
||||
}
|
||||
|
||||
if _, isTLS := c.TLSConnectionState(); !isTLS && !c.server.AllowInsecureAuth {
|
||||
if !c.authAllowed() {
|
||||
c.writeResponse(523, EnhancedCode{5, 7, 10}, "TLS is required")
|
||||
return
|
||||
}
|
||||
@@ -778,18 +789,21 @@ func (c *Conn) handleAuth(arg string) {
|
||||
var err error
|
||||
ir, err = base64.StdEncoding.DecodeString(parts[1])
|
||||
if err != nil {
|
||||
c.writeResponse(454, EnhancedCode{4, 7, 0}, "Invalid base64 data")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
newSasl, ok := c.server.auths[mechanism]
|
||||
if !ok {
|
||||
c.writeResponse(504, EnhancedCode{5, 7, 4}, "Unsupported authentication mechanism")
|
||||
sasl, err := c.auth(mechanism)
|
||||
if err != nil {
|
||||
if smtpErr, ok := err.(*SMTPError); ok {
|
||||
c.writeResponse(smtpErr.Code, smtpErr.EnhancedCode, smtpErr.Message)
|
||||
} else {
|
||||
c.writeResponse(454, EnhancedCode{4, 7, 0}, err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
sasl := newSasl(c)
|
||||
|
||||
response := ir
|
||||
for {
|
||||
challenge, done, err := sasl.Next(response)
|
||||
@@ -834,6 +848,20 @@ func (c *Conn) handleAuth(arg string) {
|
||||
c.didAuth = true
|
||||
}
|
||||
|
||||
func (c *Conn) authMechanisms() []string {
|
||||
if authSession, ok := c.Session().(AuthSession); ok {
|
||||
return authSession.AuthMechanisms()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) auth(mech string) (sasl.Server, error) {
|
||||
if authSession, ok := c.Session().(AuthSession); ok {
|
||||
return authSession.Auth(mech)
|
||||
}
|
||||
return nil, ErrAuthUnknownMechanism
|
||||
}
|
||||
|
||||
func (c *Conn) handleStartTLS() {
|
||||
if _, isTLS := c.TLSConnectionState(); isTLS {
|
||||
c.writeResponse(502, EnhancedCode{5, 5, 1}, "Already running in TLS")
|
||||
|
||||
43
vendor/github.com/emersion/go-smtp/server.go
generated
vendored
43
vendor/github.com/emersion/go-smtp/server.go
generated
vendored
@@ -10,17 +10,12 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/emersion/go-sasl"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrServerClosed = errors.New("smtp: server already closed")
|
||||
)
|
||||
|
||||
// A function that creates SASL servers.
|
||||
type SaslServerFactory func(conn *Conn) sasl.Server
|
||||
|
||||
// Logger interface is used by Server to report unexpected internal errors.
|
||||
type Logger interface {
|
||||
Printf(format string, v ...interface{})
|
||||
@@ -64,18 +59,11 @@ type Server struct {
|
||||
// Should be used only if backend supports it.
|
||||
EnableDSN bool
|
||||
|
||||
// If set, the AUTH command will not be advertised and authentication
|
||||
// attempts will be rejected. This setting overrides AllowInsecureAuth.
|
||||
AuthDisabled bool
|
||||
|
||||
// The server backend.
|
||||
Backend Backend
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
caps []string
|
||||
auths map[string]SaslServerFactory
|
||||
done chan struct{}
|
||||
wg sync.WaitGroup
|
||||
done chan struct{}
|
||||
|
||||
locker sync.Mutex
|
||||
listeners []net.Listener
|
||||
@@ -91,24 +79,7 @@ func NewServer(be Backend) *Server {
|
||||
Backend: be,
|
||||
done: make(chan struct{}, 1),
|
||||
ErrorLog: log.New(os.Stderr, "smtp/server ", log.LstdFlags),
|
||||
caps: []string{"PIPELINING", "8BITMIME", "ENHANCEDSTATUSCODES", "CHUNKING"},
|
||||
auths: map[string]SaslServerFactory{
|
||||
sasl.Plain: func(conn *Conn) sasl.Server {
|
||||
return sasl.NewPlainServer(func(identity, username, password string) error {
|
||||
if identity != "" && identity != username {
|
||||
return errors.New("identities not supported")
|
||||
}
|
||||
|
||||
sess := conn.Session()
|
||||
if sess == nil {
|
||||
panic("No session when AUTH is called")
|
||||
}
|
||||
|
||||
return sess.AuthPlain(username, password)
|
||||
})
|
||||
},
|
||||
},
|
||||
conns: make(map[*Conn]struct{}),
|
||||
conns: make(map[*Conn]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,11 +300,3 @@ func (s *Server) Shutdown(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAuth enables an authentication mechanism on this server.
|
||||
//
|
||||
// This function should not be called directly, it must only be used by
|
||||
// libraries implementing extensions of the SMTP protocol.
|
||||
func (s *Server) EnableAuth(name string, f SaslServerFactory) {
|
||||
s.auths[name] = f
|
||||
}
|
||||
|
||||
5
vendor/github.com/yuin/goldmark/README.md
generated
vendored
5
vendor/github.com/yuin/goldmark/README.md
generated
vendored
@@ -10,6 +10,8 @@ goldmark
|
||||
|
||||
goldmark is compliant with CommonMark 0.31.2.
|
||||
|
||||
- [goldmark playground](https://yuin.github.io/goldmark/playground/) : Try goldmark online. This playground is built with WASM(5-10MB).
|
||||
|
||||
Motivation
|
||||
----------------------
|
||||
I needed a Markdown parser for Go that satisfies the following requirements:
|
||||
@@ -282,7 +284,7 @@ markdown := goldmark.New(
|
||||
"https:",
|
||||
}),
|
||||
extension.WithLinkifyURLRegexp(
|
||||
xurls.Strict,
|
||||
xurls.Strict(),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -493,6 +495,7 @@ Extensions
|
||||
- [goldmark-img64](https://github.com/tenkoh/goldmark-img64): Adds support for embedding images into the document as DataURL (base64 encoded).
|
||||
- [goldmark-enclave](https://github.com/quail-ink/goldmark-enclave): Adds support for embedding youtube/bilibili video, X's [oembed tweet](https://publish.twitter.com/), [tradingview](https://www.tradingview.com/widget/)'s chart, [quail](https://quail.ink)'s widget into the document.
|
||||
- [goldmark-wiki-table](https://github.com/movsb/goldmark-wiki-table): Adds support for embedding Wiki Tables.
|
||||
- [goldmark-tgmd](https://github.com/Mad-Pixels/goldmark-tgmd): A Telegram markdown renderer that can be passed to `goldmark.WithRenderer()`.
|
||||
|
||||
### Loading extensions at runtime
|
||||
[goldmark-dynamic](https://github.com/yuin/goldmark-dynamic) allows you to write a goldmark extension in Lua and load it at runtime without re-compilation.
|
||||
|
||||
9
vendor/github.com/yuin/goldmark/renderer/html/html.go
generated
vendored
9
vendor/github.com/yuin/goldmark/renderer/html/html.go
generated
vendored
@@ -786,7 +786,14 @@ func RenderAttributes(w util.BufWriter, node ast.Node, filter util.BytesFilter)
|
||||
_, _ = w.Write(attr.Name)
|
||||
_, _ = w.WriteString(`="`)
|
||||
// TODO: convert numeric values to strings
|
||||
_, _ = w.Write(util.EscapeHTML(attr.Value.([]byte)))
|
||||
var value []byte
|
||||
switch typed := attr.Value.(type) {
|
||||
case []byte:
|
||||
value = typed
|
||||
case string:
|
||||
value = util.StringToReadOnlyBytes(typed)
|
||||
}
|
||||
_, _ = w.Write(util.EscapeHTML(value))
|
||||
_ = w.WriteByte('"')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user