// A GIN middleware providing low-fi security for personal stuff. package gin_teeny_security import "github.com/gin-gonic/gin" import "github.com/gin-contrib/sessions" import "net/http" import "net/url" import "fmt" import "io" import "html/template" // Forces you to a login page until you provide a secret code. // No CSRF protection, so any script on any page can log you // out (or in, if they know the password). // The rest of your site needs XSS protection on forms or any site on the // net can inject stuff. If you're sending open CORS headers this // would be particularly bad. func RequiresSecretAccessCode(secretAccessCode, path string) gin.HandlerFunc { cfg := &Config{ Path: path, Secret: secretAccessCode, } return cfg.Middleware } type Config struct { Path string // defaults to login Secret string RequireAuth func(*gin.Context) bool // defaults to always requiring auth if unset Template *template.Template SaveKeyToSession func(*gin.Context, string) GetKeyFromSession func(*gin.Context) string } func (c Config) saveKey(ctx *gin.Context, k string) { if c.SaveKeyToSession == nil { c.SaveKeyToSession = DefaultSetSession } c.SaveKeyToSession(ctx, k) } func (c Config) getKey(ctx *gin.Context) string { if c.GetKeyFromSession == nil { c.GetKeyFromSession = DefaultGetSession } return c.GetKeyFromSession(ctx) } func DefaultSetSession(c *gin.Context, secret string) { session := sessions.Default(c) session.Set("secretAccessCode", secret) session.Save() } func DefaultGetSession(c *gin.Context) string { session := sessions.Default(c) str, ok := session.Get("secretAccessCode").(string) if !ok { fmt.Println(session.Get("secretAccessCode")) return "" } return str } func (c Config) path() string { if c.Path == "" { return "/login/" } return c.Path } func (c Config) requireAuth(ctx *gin.Context) bool { if ctx.Request.Header.Get("Authorization") == c.Secret { return false } return c.RequireAuth == nil || c.RequireAuth(ctx) } func (c Config) template() *template.Template { if c.Template == nil { return DEFAULT_LOGIN_PAGE } return c.Template } func (c Config) ExecTemplate(w io.Writer, message, returnUrl string) error { return c.template().Execute(w, LoginPageParams{ Message: message, Path: c.path() + "?" + url.Values{"return": []string{returnUrl}}.Encode(), }) } type LoginPageParams struct { Message string Path string } var DEFAULT_LOGIN_PAGE = template.Must(template.New("login").Parse(`