Add explicit login functionality
This commit is contained in:
+34
-23
@@ -24,11 +24,13 @@ type Server struct {
|
||||
tokens *auth.File
|
||||
log *slog.Logger
|
||||
|
||||
pages map[string]*template.Template
|
||||
handler http.Handler
|
||||
limiter *limiter
|
||||
deleteLimiter *limiter // consumed only by failed deletions
|
||||
slots chan struct{} // bounds uploads in flight
|
||||
pages map[string]*template.Template
|
||||
handler http.Handler
|
||||
limiter *limiter
|
||||
// authLimiter is consumed only by failed credential attempts - a wrong
|
||||
// delete token or a wrong login - so correct ones are never delayed.
|
||||
authLimiter *limiter
|
||||
slots chan struct{} // bounds uploads in flight
|
||||
|
||||
now func() time.Time // swappable in tests
|
||||
}
|
||||
@@ -39,15 +41,15 @@ func New(cfg *config.Config, st *store.Store, tokens *auth.File, log *slog.Logge
|
||||
return nil, err
|
||||
}
|
||||
s := &Server{
|
||||
cfg: cfg,
|
||||
store: st,
|
||||
tokens: tokens,
|
||||
log: log,
|
||||
pages: pages,
|
||||
limiter: newLimiter(cfg.UploadRate, cfg.UploadBurst),
|
||||
deleteLimiter: newLimiter(120, 20),
|
||||
slots: make(chan struct{}, cfg.MaxConcurrent),
|
||||
now: time.Now,
|
||||
cfg: cfg,
|
||||
store: st,
|
||||
tokens: tokens,
|
||||
log: log,
|
||||
pages: pages,
|
||||
limiter: newLimiter(cfg.UploadRate, cfg.UploadBurst),
|
||||
authLimiter: newLimiter(120, 20),
|
||||
slots: make(chan struct{}, cfg.MaxConcurrent),
|
||||
now: time.Now,
|
||||
}
|
||||
s.handler = s.routes()
|
||||
return s, nil
|
||||
@@ -65,11 +67,14 @@ func (s *Server) routes() http.Handler {
|
||||
mux.HandleFunc("GET /d/{id}", s.handleDownload)
|
||||
mux.HandleFunc("GET /i/{id}", s.handleInfo)
|
||||
mux.HandleFunc("POST /api/d/{id}/delete", s.handleDelete)
|
||||
mux.HandleFunc("POST /api/forget", s.handleForget)
|
||||
mux.HandleFunc("GET /login", s.handleLoginPage)
|
||||
mux.HandleFunc("POST /login", s.handleLogin)
|
||||
mux.HandleFunc("POST /logout", s.handleLogout)
|
||||
mux.Handle("GET /static/", http.StripPrefix("/static/", s.staticHandler()))
|
||||
mux.HandleFunc("/", s.handleNotFound)
|
||||
|
||||
var h http.Handler = mux
|
||||
h = s.requireSameOrigin(h)
|
||||
h = s.securityHeaders(h)
|
||||
|
||||
if s.cfg.BasePath == "/" {
|
||||
@@ -153,7 +158,8 @@ func bearer(r *http.Request) string {
|
||||
|
||||
// --- rendering -----------------------------------------------------------
|
||||
|
||||
var pageNames = []string{"index.html", "result.html", "info.html", "error.html", "admin.html"}
|
||||
var pageNames = []string{"index.html", "result.html", "info.html", "error.html",
|
||||
"admin.html", "login.html"}
|
||||
|
||||
// parsePages pairs each page with the shared layout. They cannot all be parsed
|
||||
// into one template set because every page defines "content".
|
||||
@@ -175,17 +181,22 @@ type page struct {
|
||||
Base string
|
||||
Title string
|
||||
Script bool
|
||||
Admin bool // show the administration link in the header
|
||||
|
||||
// User is the logged-in token's name, empty when nobody is logged in. The
|
||||
// header renders the whole session state from these two fields, so every
|
||||
// page agrees about who you are without any script involved.
|
||||
User string
|
||||
Admin bool
|
||||
}
|
||||
|
||||
// page builds the common fields, resolving whether the caller is an admin so
|
||||
// the header can offer the link only to someone who can use it.
|
||||
// page builds the common fields, resolving the session so the header can show
|
||||
// who is logged in and offer only the links they can use.
|
||||
func (s *Server) page(r *http.Request, title string, script bool) page {
|
||||
admin := false
|
||||
if lim, err := s.limitsFor(credential(r)); err == nil {
|
||||
admin = lim.Admin
|
||||
p := page{Base: s.cfg.BasePath, Title: title, Script: script}
|
||||
if lim, err := s.limitsFor(cookieCredential(r)); err == nil {
|
||||
p.User, p.Admin = lim.Name, lim.Admin
|
||||
}
|
||||
return page{Base: s.cfg.BasePath, Title: title, Script: script, Admin: admin}
|
||||
return p
|
||||
}
|
||||
|
||||
func (s *Server) render(w http.ResponseWriter, status int, name string, data any) {
|
||||
|
||||
Reference in New Issue
Block a user