Bezbednost — security headers, fail2ban logovanje, bruteforce zaštita, CSRF zaštita

This commit is contained in:
2026-06-03 21:38:16 +02:00
parent 974d76360a
commit ed7ae605b2
15 changed files with 352 additions and 18 deletions
+79
View File
@@ -0,0 +1,79 @@
package sqlite
import (
"context"
"database/sql"
"fmt"
"time"
)
// PokusajiPrijaveRepo implementira db.PokusajiPrijaveRepository nad SQLite
type PokusajiPrijaveRepo struct {
db *sql.DB
}
// NoviPokusajiPrijaveRepo kreira novi repozitorijum za praćenje pokušaja prijave
func NoviPokusajiPrijaveRepo(db *sql.DB) *PokusajiPrijaveRepo {
return &PokusajiPrijaveRepo{db: db}
}
// Zabeleži upisuje novi pokušaj prijave (uspešan ili neuspešan)
func (r *PokusajiPrijaveRepo) Zabeleži(ctx context.Context, ip, korisnickoIme string, uspeh bool) error {
u := 0
if uspeh {
u = 1
}
_, err := r.db.ExecContext(ctx,
"INSERT INTO pokusaji_prijave (ip, korisnicko_ime, uspeh) VALUES (?, ?, ?)",
ip, korisnickoIme, u,
)
if err != nil {
return fmt.Errorf("ntech: PokusajiPrijaveRepo.Zabeleži: %w", err)
}
return nil
}
// BrojNeuspeha vraća broj neuspelih pokušaja za datu IP adresu od zadatog trenutka
func (r *PokusajiPrijaveRepo) BrojNeuspeha(ctx context.Context, ip string, od time.Time) (int, error) {
var n int
err := r.db.QueryRowContext(ctx,
"SELECT COUNT(*) FROM pokusaji_prijave WHERE ip = ? AND uspeh = 0 AND vreme > ?",
ip, od.UTC().Format("2006-01-02 15:04:05"),
).Scan(&n)
if err != nil {
return 0, fmt.Errorf("ntech: PokusajiPrijaveRepo.BrojNeuspeha: %w", err)
}
return n, nil
}
// VremePoslednjeg vraća vreme poslednjeg neuspelog pokušaja za datu IP adresu od zadatog trenutka
func (r *PokusajiPrijaveRepo) VremePoslednjeg(ctx context.Context, ip string, od time.Time) (time.Time, bool, error) {
var s sql.NullString
err := r.db.QueryRowContext(ctx,
"SELECT MAX(vreme) FROM pokusaji_prijave WHERE ip = ? AND uspeh = 0 AND vreme > ?",
ip, od.UTC().Format("2006-01-02 15:04:05"),
).Scan(&s)
if err != nil {
return time.Time{}, false, fmt.Errorf("ntech: PokusajiPrijaveRepo.VremePoslednjeg: %w", err)
}
if !s.Valid || s.String == "" {
return time.Time{}, false, nil
}
t, err := time.ParseInLocation("2006-01-02 15:04:05", s.String, time.UTC)
if err != nil {
return time.Time{}, false, fmt.Errorf("ntech: PokusajiPrijaveRepo.VremePoslednjeg: parse: %w", err)
}
return t, true, nil
}
// ObrisiStare briše sve zapise starije od zadatog trenutka
func (r *PokusajiPrijaveRepo) ObrisiStare(ctx context.Context, pre time.Time) error {
_, err := r.db.ExecContext(ctx,
"DELETE FROM pokusaji_prijave WHERE vreme < ?",
pre.UTC().Format("2006-01-02 15:04:05"),
)
if err != nil {
return fmt.Errorf("ntech: PokusajiPrijaveRepo.ObrisiStare: %w", err)
}
return nil
}