Admin endpoint: ENV/file admin key, --reset-admin-key, settings API wired into ratelimit/max-bytes/default-expiry/burn-window (#40)
This commit is contained in:
@@ -419,8 +419,10 @@ func writeErr(w http.ResponseWriter, status int, msg string) {
|
||||
}
|
||||
|
||||
type apiServer struct {
|
||||
store *Store
|
||||
cfg Config
|
||||
store *Store
|
||||
cfg Config
|
||||
settings *settingsStore
|
||||
adminKey string
|
||||
}
|
||||
|
||||
func (a *apiServer) routes() http.Handler {
|
||||
@@ -429,6 +431,11 @@ func (a *apiServer) routes() http.Handler {
|
||||
r.Use(middleware.Timeout(30 * time.Second))
|
||||
r.Use(viewerCookieMiddleware)
|
||||
|
||||
// admin (#40): HTML page is open (key entry via form); API is key-guarded
|
||||
r.Get("/admin", a.handleAdminPage)
|
||||
r.Get("/admin/api/settings", a.adminAuth(a.handleAdminGetSettings, a.adminKey))
|
||||
r.Post("/admin/api/settings", a.adminAuth(a.handleAdminPostSettings, a.adminKey))
|
||||
|
||||
// API
|
||||
r.Route("/api", func(r chi.Router) {
|
||||
r.Post("/pastes", a.handleCreatePaste)
|
||||
@@ -521,10 +528,15 @@ func (a *apiServer) handleCreatePaste(w http.ResponseWriter, r *http.Request) {
|
||||
writeErr(w, 400, "content is required")
|
||||
return
|
||||
}
|
||||
if int64(len(p.Content)) > a.cfg.MaxTextBytes {
|
||||
writeErr(w, 413, fmt.Sprintf("content exceeds max %d bytes", a.cfg.MaxTextBytes))
|
||||
if int64(len(p.Content)) > a.settings.get().MaxContentBytes { // #40: admin-tunable
|
||||
writeErr(w, 413, fmt.Sprintf("content exceeds max %d bytes", a.settings.get().MaxContentBytes))
|
||||
return
|
||||
}
|
||||
// #40: admin-configurable default expiry
|
||||
if (p.ExpiresIn == nil || *p.ExpiresIn == "") && a.settings.get().DefaultExpiry != "" {
|
||||
def := a.settings.get().DefaultExpiry
|
||||
p.ExpiresIn = &def
|
||||
}
|
||||
p.ViewerID = currentViewerID(r)
|
||||
created, err := a.store.CreatePaste(&p)
|
||||
if err != nil {
|
||||
@@ -770,6 +782,11 @@ func templateEsc(s string) string {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// #40: --reset-admin-key regenerates the admin key and exits.
|
||||
if len(os.Args) > 1 && (os.Args[1] == "--reset-admin-key") {
|
||||
handleResetAdminKey(envOr("PALETTE_DB", "palette.db"))
|
||||
return
|
||||
}
|
||||
cfg := Config{
|
||||
Addr: envOr("PALETTE_ADDR", ":8080"),
|
||||
DBPath: envOr("PALETTE_DB", "palette.db"),
|
||||
@@ -782,12 +799,19 @@ func main() {
|
||||
}
|
||||
store.StartSweeper(time.Minute)
|
||||
|
||||
adminKey, err := resolveAdminKey(cfg.DBPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ss := loadSettingsStore(cfg.DBPath, cfg)
|
||||
|
||||
ui, err := NewWebUI()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
webUIInstance = ui
|
||||
srv := &apiServer{store: store, cfg: cfg}
|
||||
srv := &apiServer{store: store, cfg: cfg, settings: ss, adminKey: adminKey}
|
||||
globalSettingsFn = func() Settings { return ss.get() }
|
||||
log.Printf("palette listening on %s", cfg.Addr)
|
||||
log.Fatal(http.ListenAndServe(cfg.Addr, srv.routes()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user