175 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			Go
		
	
	
	
package pagewriter
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"net/http"
 | 
						|
)
 | 
						|
 | 
						|
// Writer is an interface for rendering html templates for both sign-in and
 | 
						|
// error pages.
 | 
						|
// It can also be used to write errors for the http.ReverseProxy used in the
 | 
						|
// upstream package.
 | 
						|
type Writer interface {
 | 
						|
	WriteSignInPage(rw http.ResponseWriter, req *http.Request, redirectURL string, statusCode int)
 | 
						|
	WriteErrorPage(rw http.ResponseWriter, opts ErrorPageOpts)
 | 
						|
	ProxyErrorHandler(rw http.ResponseWriter, req *http.Request, proxyErr error)
 | 
						|
	WriteRobotsTxt(rw http.ResponseWriter, req *http.Request)
 | 
						|
}
 | 
						|
 | 
						|
// pageWriter implements the Writer interface
 | 
						|
type pageWriter struct {
 | 
						|
	*errorPageWriter
 | 
						|
	*signInPageWriter
 | 
						|
	*staticPageWriter
 | 
						|
}
 | 
						|
 | 
						|
// Opts contains all options required to configure the template
 | 
						|
// rendering within OAuth2 Proxy.
 | 
						|
type Opts struct {
 | 
						|
	// TemplatesPath is the path from which to load custom templates for the sign-in and error pages.
 | 
						|
	TemplatesPath string
 | 
						|
 | 
						|
	// ProxyPrefix is the prefix under which OAuth2 Proxy pages are served.
 | 
						|
	ProxyPrefix string
 | 
						|
 | 
						|
	// Footer is the footer to be displayed at the bottom of the page.
 | 
						|
	// If not set, a default footer will be used.
 | 
						|
	Footer string
 | 
						|
 | 
						|
	// Version is the OAuth2 Proxy version to be used in the default footer.
 | 
						|
	Version string
 | 
						|
 | 
						|
	// Debug determines whether errors pages should be rendered with detailed
 | 
						|
	// errors.
 | 
						|
	Debug bool
 | 
						|
 | 
						|
	// DisplayLoginForm determines whether or not the basic auth password form is displayed on the sign-in page.
 | 
						|
	DisplayLoginForm bool
 | 
						|
 | 
						|
	// ProviderName is the name of the provider that should be displayed on the login button.
 | 
						|
	ProviderName string
 | 
						|
 | 
						|
	// SignInMessage is the messge displayed above the login button.
 | 
						|
	SignInMessage string
 | 
						|
 | 
						|
	// CustomLogo is the path or URL to a logo to be displayed on the sign in page.
 | 
						|
	// The logo can be either PNG, JPG/JPEG or SVG.
 | 
						|
	// If a URL is used, image support depends on the browser.
 | 
						|
	CustomLogo string
 | 
						|
}
 | 
						|
 | 
						|
// NewWriter constructs a Writer from the options given to allow
 | 
						|
// rendering of sign-in and error pages.
 | 
						|
func NewWriter(opts Opts) (Writer, error) {
 | 
						|
	templates, err := loadTemplates(opts.TemplatesPath)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("error loading templates: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	logoData, err := loadCustomLogo(opts.CustomLogo)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("error loading logo: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	errorPage := &errorPageWriter{
 | 
						|
		template:    templates.Lookup("error.html"),
 | 
						|
		proxyPrefix: opts.ProxyPrefix,
 | 
						|
		footer:      opts.Footer,
 | 
						|
		version:     opts.Version,
 | 
						|
		debug:       opts.Debug,
 | 
						|
	}
 | 
						|
 | 
						|
	signInPage := &signInPageWriter{
 | 
						|
		template:         templates.Lookup("sign_in.html"),
 | 
						|
		errorPageWriter:  errorPage,
 | 
						|
		proxyPrefix:      opts.ProxyPrefix,
 | 
						|
		providerName:     opts.ProviderName,
 | 
						|
		signInMessage:    opts.SignInMessage,
 | 
						|
		footer:           opts.Footer,
 | 
						|
		version:          opts.Version,
 | 
						|
		displayLoginForm: opts.DisplayLoginForm,
 | 
						|
		logoData:         logoData,
 | 
						|
	}
 | 
						|
 | 
						|
	staticPages, err := newStaticPageWriter(opts.TemplatesPath, errorPage)
 | 
						|
	if err != nil {
 | 
						|
		return nil, fmt.Errorf("error loading static page writer: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return &pageWriter{
 | 
						|
		errorPageWriter:  errorPage,
 | 
						|
		signInPageWriter: signInPage,
 | 
						|
		staticPageWriter: staticPages,
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// WriterFuncs is an implementation of the PageWriter interface based
 | 
						|
// on override functions.
 | 
						|
// If any of the funcs are not provided, a default implementation will be used.
 | 
						|
// This is primarily for us in testing.
 | 
						|
type WriterFuncs struct {
 | 
						|
	SignInPageFunc func(rw http.ResponseWriter, req *http.Request, redirectURL string, statusCode int)
 | 
						|
	ErrorPageFunc  func(rw http.ResponseWriter, opts ErrorPageOpts)
 | 
						|
	ProxyErrorFunc func(rw http.ResponseWriter, req *http.Request, proxyErr error)
 | 
						|
	RobotsTxtfunc  func(rw http.ResponseWriter, req *http.Request)
 | 
						|
}
 | 
						|
 | 
						|
// WriteSignInPage implements the Writer interface.
 | 
						|
// If the SignInPageFunc is provided, this will be used, else a default
 | 
						|
// implementation will be used.
 | 
						|
func (w *WriterFuncs) WriteSignInPage(rw http.ResponseWriter, req *http.Request, redirectURL string, statusCode int) {
 | 
						|
	if w.SignInPageFunc != nil {
 | 
						|
		w.SignInPageFunc(rw, req, redirectURL, statusCode)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if _, err := rw.Write([]byte("Sign In")); err != nil {
 | 
						|
		rw.WriteHeader(http.StatusInternalServerError)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// WriteErrorPage implements the Writer interface.
 | 
						|
// If the ErrorPageFunc is provided, this will be used, else a default
 | 
						|
// implementation will be used.
 | 
						|
func (w *WriterFuncs) WriteErrorPage(rw http.ResponseWriter, opts ErrorPageOpts) {
 | 
						|
	if w.ErrorPageFunc != nil {
 | 
						|
		w.ErrorPageFunc(rw, opts)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	rw.WriteHeader(opts.Status)
 | 
						|
	errMsg := fmt.Sprintf("%d - %v", opts.Status, opts.AppError)
 | 
						|
	if _, err := rw.Write([]byte(errMsg)); err != nil {
 | 
						|
		rw.WriteHeader(http.StatusInternalServerError)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// ProxyErrorHandler implements the Writer interface.
 | 
						|
// If the ProxyErrorFunc is provided, this will be used, else a default
 | 
						|
// implementation will be used.
 | 
						|
func (w *WriterFuncs) ProxyErrorHandler(rw http.ResponseWriter, req *http.Request, proxyErr error) {
 | 
						|
	if w.ProxyErrorFunc != nil {
 | 
						|
		w.ProxyErrorFunc(rw, req, proxyErr)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	w.WriteErrorPage(rw, ErrorPageOpts{
 | 
						|
		Status:   http.StatusBadGateway,
 | 
						|
		AppError: proxyErr.Error(),
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
// WriteRobotsTxt implements the Writer interface.
 | 
						|
// If the RobotsTxtfunc is provided, this will be used, else a default
 | 
						|
// implementation will be used.
 | 
						|
func (w *WriterFuncs) WriteRobotsTxt(rw http.ResponseWriter, req *http.Request) {
 | 
						|
	if w.RobotsTxtfunc != nil {
 | 
						|
		w.RobotsTxtfunc(rw, req)
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if _, err := rw.Write([]byte("Allow: *")); err != nil {
 | 
						|
		rw.WriteHeader(http.StatusInternalServerError)
 | 
						|
	}
 | 
						|
}
 |