package gig

import (

"crypto/md5"

"crypto/tls"

"crypto/x509"

"errors"

"fmt"

"testing"

"github.com/matryer/is"

)

func TestPassAuth(t *testing.T) {

var (

is = is.New(t)

g = New()

invalidErr = errors.New("invalid credentials")

goodCert = x509.Certificate{Raw: []byte{1}}

newCert = x509.Certificate{Raw: []byte{2}}

mw = PassAuth(func(sig string, c Context) (string, error) {

if sig == fmt.Sprintf("%x", md5.Sum(goodCert.Raw)) {

return "", nil

}

return "/login", nil

})

)

g.Handle("/", func(c Context) error {

return c.Gemini("ok")

})

g.PassAuthLoginHandle("/login", func(u, p, sig string, c Context) (string, error) {

if u == "valid-user" && p == "secret" {

return "/private", nil

}

return "", invalidErr

})

g.Handle("/private", func(c Context) error {

return c.Gemini("private")

}, mw)

// Public endpoint

c, res := g.NewFakeContext("/", nil)

g.ServeGemini(c)

is.Equal(res.Written, "20 text/gemini\r\nok")

// No certificate

c, res = g.NewFakeContext("/private", nil)

g.ServeGemini(c)

is.Equal(res.Written, "60 Please create a certificate\r\n")

// New certificate

c, res = g.NewFakeContext("/private", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "30 /login\r\n")

// Try login with new certificate

c, res = g.NewFakeContext("/login", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "10 Enter username\r\n")

c, res = g.NewFakeContext("/login?valid-user", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "30 /login/valid-user\r\n")

c, res = g.NewFakeContext("/login/valid-user", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "11 Enter password\r\n")

c, res = g.NewFakeContext("/login/valid-user?bad-pass", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "50 invalid credentials\r\n")

c, res = g.NewFakeContext("/login/valid-user?secret", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "30 /private\r\n")

// Logged in certificate

c, res = g.NewFakeContext("/private", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&goodCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "20 text/gemini\r\nprivate")

}

func TestPassAuth_Errors(t *testing.T) {

var (

is = is.New(t)

g = New()

newCert = x509.Certificate{Raw: []byte{2}}

mw = PassAuth(func(sig string, c Context) (string, error) {

return "/login", errors.New("oops")

})

)

g.Handle("/", func(c Context) error {

return c.Gemini("ok")

})

g.PassAuthLoginHandle("/login", func(u, p, sig string, c Context) (string, error) {

return "", errors.New("oops")

})

g.Handle("/private", func(c Context) error {

return c.Gemini("private")

}, mw)

// CertCheck fails

c, res := g.NewFakeContext("/private", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "59 Try again later\r\n")

// Bad username

c, res = g.NewFakeContext("/login?%%", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "59 Invalid username received\r\n")

// Bad password

c, res = g.NewFakeContext("/login/valid-user?%%", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "59 Invalid password received\r\n")

// Login fails

c, res = g.NewFakeContext("/login/valid-user?secret", &tls.ConnectionState{

PeerCertificates: []*x509.Certificate{&newCert},

})

g.ServeGemini(c)

is.Equal(res.Written, "50 oops\r\n")

}


Source