Nova stranica /admin/blokirane-ip — lista IP adresa sa previše neuspelih pokušaja prijave (broj neuspeha, poslednji pokušaj, preostalo vreme zaključavanja) i dugme za ručno odblokiranje. Nova dozvola 'bezbednost.odblokiraj', namerno rezervisana isključivo za ulogu superadmin (admin je nema — odblokiranje zaobilazi bruteforce zaštitu). Repo metode PokusajiPrijaveRepo.ListaBlokiranih/Odblokiraj.
82 lines
2.6 KiB
Go
82 lines
2.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
ntechsqlite "ntech/internal/db/sqlite"
|
|
"ntech/internal/middleware"
|
|
"ntech/internal/model"
|
|
)
|
|
|
|
// stavkaBlokiraneIP je jedan red na stranici blokiranih IP adresa, sa
|
|
// unapred izračunatim preostalim vremenom zaključavanja (ili "" ako je isteklo).
|
|
type stavkaBlokiraneIP struct {
|
|
model.BlokiranaIP
|
|
Preostalo string
|
|
}
|
|
|
|
type podaciBlokiraneIP struct {
|
|
model.PodaciStranice
|
|
Lista []stavkaBlokiraneIP
|
|
}
|
|
|
|
// AdminBlokiraneIP prikazuje IP adrese trenutno zaključane zbog previše neuspelih
|
|
// pokušaja prijave, sa mogućnošću ručnog odblokiranja (superadmin).
|
|
func (h *Handler) AdminBlokiraneIP(w http.ResponseWriter, r *http.Request) {
|
|
if _, ok := h.zahtevajDozvolu(w, r, "bezbednost.odblokiraj"); !ok {
|
|
return
|
|
}
|
|
podesavanja, err := ntechsqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
|
if err != nil {
|
|
http.Error(w, "Greška pri učitavanju podešavanja", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
ps := h.popuniPodaciStranice(r, podesavanja)
|
|
ps.Stranica = "blokirane-ip"
|
|
ps.NaslovStranice = "Blokirane IP adrese"
|
|
|
|
od := time.Now().Add(-prozorPrijave)
|
|
blokirane, err := h.PokusajiRepo.ListaBlokiranih(r.Context(), od, maxNeuspehaPrijave)
|
|
if err != nil {
|
|
http.Error(w, "Greška pri učitavanju blokiranih IP adresa", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
lista := make([]stavkaBlokiraneIP, 0, len(blokirane))
|
|
for _, b := range blokirane {
|
|
preostalo, zakljucano := h.preostaloBruteforce(r.Context(), b.IP, od)
|
|
if !zakljucano {
|
|
continue
|
|
}
|
|
lista = append(lista, stavkaBlokiraneIP{BlokiranaIP: b, Preostalo: preostalo})
|
|
}
|
|
|
|
h.renderujTemplate(w, "blokirane_ip", podaciBlokiraneIP{PodaciStranice: ps, Lista: lista})
|
|
}
|
|
|
|
// AdminOdblokirajIP briše neuspele pokušaje prijave za datu IP adresu, čime se ona
|
|
// odmah oslobađa bruteforce blokade.
|
|
func (h *Handler) AdminOdblokirajIP(w http.ResponseWriter, r *http.Request) {
|
|
if _, ok := h.zahtevajDozvolu(w, r, "bezbednost.odblokiraj"); !ok {
|
|
return
|
|
}
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "Greška pri čitanju forme", http.StatusBadRequest)
|
|
return
|
|
}
|
|
ip := strings.TrimSpace(r.FormValue("ip"))
|
|
if ip == "" {
|
|
http.Redirect(w, r, "/admin/blokirane-ip", http.StatusSeeOther)
|
|
return
|
|
}
|
|
if err := h.PokusajiRepo.Odblokiraj(r.Context(), ip); err != nil {
|
|
middleware.SetFlash(w, r, h.DB, "greska", "Odblokiranje nije uspelo.")
|
|
http.Redirect(w, r, "/admin/blokirane-ip", http.StatusSeeOther)
|
|
return
|
|
}
|
|
middleware.SetFlash(w, r, h.DB, "uspeh", "IP adresa "+ip+" je odblokirana.")
|
|
http.Redirect(w, r, "/admin/blokirane-ip", http.StatusSeeOther)
|
|
}
|