Files
GoNtech/internal/handler/utils_test.go
T
Dasko 49296e4315 Bezbednosne i integritetne popravke iz pregleda koda
- foreign_keys pragma po konekciji (DSN _pragma) — ranije aktivna na
  samo delu konekcija iz pula, rizik siročadi u bazi pri brisanju
- busy_timeout + _txlock=immediate za konkurentan pristup SQLite bazi
- ispravljen DnevniPrometMaloprodaje (DATE() -> substr) — dnevni pazar
  za KIR/KPO je bio uvek nula
- rate-limit (isti IP-bruteforce brojač) dodat na TOTP/2FA verifikaciju
- ispravljen nil-pointer u DodajDeloNalogu + uklonjeni debug logovi
- izvuciIP prihvata X-Real-IP/X-Forwarded-For samo sa poverljive
  (loopback/privatne) adrese — sprečava zaobilaženje bruteforce brave
- ispravljen naziv dozvole podesavanja.izmena -> podesavanja.izmeni
- brisanje artikala/kategorija prebačeno sa GET na POST (CSRF zaštita)
2026-07-03 23:00:44 +02:00

77 lines
2.3 KiB
Go

package handler
import (
"net/http"
"testing"
)
func TestIzvuciIP(t *testing.T) {
testovi := []struct {
naziv string
realIP string
forwarded string
remoteAddr string
ocek string
}{
{"X-Real-IP ima prioritet kad je proxy poverljiv (loopback)", "1.2.3.4", "9.9.9.9", "127.0.0.1:1234", "1.2.3.4"},
{"X-Real-IP ima prioritet kad je proxy poverljiv (privatna Docker mreža)", "1.2.3.4", "9.9.9.9", "172.18.0.1:1234", "1.2.3.4"},
{"poslednji X-Forwarded-For kad je proxy poverljiv", "", "1.1.1.1, 2.2.2.2, 3.3.3.3", "127.0.0.1:1234", "3.3.3.3"},
{"zaglavlje se IGNORIŠE kad RemoteAddr nije poverljiv (javna adresa — spoofing)", "1.2.3.4", "", "5.5.5.5:1234", "5.5.5.5"},
{"RemoteAddr bez porta kad nema zaglavlja", "", "", "5.5.5.5:1234", "5.5.5.5"},
{"RemoteAddr kakav jeste ako nije host:port", "", "", "neispravan", "neispravan"},
}
for _, tt := range testovi {
t.Run(tt.naziv, func(t *testing.T) {
r, _ := http.NewRequest("GET", "/", nil)
r.RemoteAddr = tt.remoteAddr
if tt.realIP != "" {
r.Header.Set("X-Real-IP", tt.realIP)
}
if tt.forwarded != "" {
r.Header.Set("X-Forwarded-For", tt.forwarded)
}
if got := izvuciIP(r); got != tt.ocek {
t.Errorf("izvuciIP() = %q, očekivano %q", got, tt.ocek)
}
})
}
}
func TestParseOpcionuCenu(t *testing.T) {
if got := parseOpcionuCenu(" "); got != nil {
t.Errorf("prazan unos → nil, dobijeno %v", *got)
}
if got := parseOpcionuCenu("abc"); got != nil {
t.Errorf("neispravan broj → nil, dobijeno %v", *got)
}
if got := parseOpcionuCenu("-5"); got != nil {
t.Errorf("negativan broj → nil, dobijeno %v", *got)
}
if got := parseOpcionuCenu("1250.50"); got == nil || *got != 1250.50 {
t.Errorf("ispravan broj → 1250.50, dobijeno %v", got)
}
}
func TestValidnoImeBackupa(t *testing.T) {
ispravna := []string{"ntech_20260612_153000.db"}
for _, ime := range ispravna {
if !validnoImeBackupa.MatchString(ime) {
t.Errorf("%q bi trebalo da je ispravno", ime)
}
}
// anti path-traversal i neispravni formati
neispravna := []string{
"../ntech_20260612_153000.db",
"ntech_20260612_153000.db.bak",
"ntech_2026_153000.db",
"ntech_20260612_153000.sqlite",
"/etc/passwd",
"ntech_20260612_153000.db/../x",
}
for _, ime := range neispravna {
if validnoImeBackupa.MatchString(ime) {
t.Errorf("%q NE bi smelo da prođe", ime)
}
}
}