158 lines
4.8 KiB
Go
158 lines
4.8 KiB
Go
package webui
|
|
|
|
import (
|
|
"net"
|
|
"net/http"
|
|
|
|
"mailgoserver/internal/db"
|
|
)
|
|
|
|
func (a *App) ipsList(w http.ResponseWriter, r *http.Request) {
|
|
ips, err := a.DB.ListWhitelistedIPs()
|
|
if err != nil {
|
|
setFlash(w, "error", "Error loading IP whitelist")
|
|
}
|
|
scope := scopeFromContext(r)
|
|
var pairs [][2]any
|
|
for _, ip := range ips {
|
|
if !scope.Allowed(ip.DomainID) {
|
|
continue
|
|
}
|
|
pairs = append(pairs, [2]any{ip.WhitelistedIP, M{"domain_name": ip.DomainName}})
|
|
}
|
|
a.render(w, r, "ips.html", M{"active": "ips", "ips": pairs})
|
|
}
|
|
|
|
func (a *App) addIPForm(w http.ResponseWriter, r *http.Request) {
|
|
domains, _ := a.accessibleDomains(r)
|
|
a.render(w, r, "add_ip.html", M{"active": "ips", "domains": domains, "prefill_ip": r.URL.Query().Get("ip")})
|
|
}
|
|
|
|
// addIP mirrors ip_whitelist.py's add_ip() POST branch: IPv4-only validation via
|
|
// net.ParseIP + To4(), matching Python's socket.inet_aton behavior (CIDR is rejected
|
|
// here despite edit_ip.html's placeholder implying CIDR support — that mismatch is
|
|
// preserved from the Python version).
|
|
func (a *App) addIP(w http.ResponseWriter, r *http.Request) {
|
|
ip := r.FormValue("ip_address")
|
|
domainID := int64(atoi(r.FormValue("domain_id")))
|
|
storeMessage := r.FormValue("store_message_content") == "on"
|
|
|
|
if net.ParseIP(ip).To4() == nil || domainID == 0 {
|
|
setFlash(w, "error", "A valid IPv4 address and domain are required")
|
|
http.Redirect(w, r, Prefix+"/ips/add", http.StatusFound)
|
|
return
|
|
}
|
|
if !requireDomainAccess(w, r, domainID) {
|
|
return
|
|
}
|
|
if exists, _ := a.DB.IPPairExists(ip, domainID, -1); exists {
|
|
setFlash(w, "error", "This IP is already whitelisted for this domain")
|
|
http.Redirect(w, r, Prefix+"/ips/add", http.StatusFound)
|
|
return
|
|
}
|
|
if _, err := a.DB.CreateWhitelistedIP(ip, domainID, storeMessage); err != nil {
|
|
setFlash(w, "error", "Error adding IP")
|
|
http.Redirect(w, r, Prefix+"/ips/add", http.StatusFound)
|
|
return
|
|
}
|
|
setFlash(w, "success", "IP address whitelisted successfully")
|
|
http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
|
|
}
|
|
|
|
// ipWithAccess fetches a whitelisted-IP row by path ID and confirms it belongs to a
|
|
// domain the current admin can manage.
|
|
func (a *App) ipWithAccess(w http.ResponseWriter, r *http.Request) (rec *db.WhitelistedIP, ok bool) {
|
|
rec, err := a.DB.GetWhitelistedIPByID(pathID(r))
|
|
if err != nil || rec == nil {
|
|
http.NotFound(w, r)
|
|
return nil, false
|
|
}
|
|
if !requireDomainAccess(w, r, rec.DomainID) {
|
|
return nil, false
|
|
}
|
|
return rec, true
|
|
}
|
|
|
|
func (a *App) disableIP(w http.ResponseWriter, r *http.Request) {
|
|
rec, ok := a.ipWithAccess(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := a.DB.SetWhitelistedIPActive(rec.ID, false); err != nil {
|
|
setFlash(w, "error", "Error disabling IP")
|
|
} else {
|
|
setFlash(w, "success", "IP disabled")
|
|
}
|
|
http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
|
|
}
|
|
|
|
func (a *App) enableIP(w http.ResponseWriter, r *http.Request) {
|
|
rec, ok := a.ipWithAccess(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := a.DB.SetWhitelistedIPActive(rec.ID, true); err != nil {
|
|
setFlash(w, "error", "Error enabling IP")
|
|
} else {
|
|
setFlash(w, "success", "IP enabled")
|
|
}
|
|
http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
|
|
}
|
|
|
|
func (a *App) removeIP(w http.ResponseWriter, r *http.Request) {
|
|
rec, ok := a.ipWithAccess(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
if err := a.DB.RemoveWhitelistedIP(rec.ID); err != nil {
|
|
setFlash(w, "error", "Error removing IP")
|
|
} else {
|
|
setFlash(w, "success", "IP permanently removed")
|
|
}
|
|
http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
|
|
}
|
|
|
|
func (a *App) editIPForm(w http.ResponseWriter, r *http.Request) {
|
|
rec, ok := a.ipWithAccess(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
domains, _ := a.accessibleDomains(r)
|
|
a.render(w, r, "edit_ip.html", M{"active": "ips", "ip_record": rec, "domains": domains})
|
|
}
|
|
|
|
// editIP mirrors ip_whitelist.py's edit_ip() POST branch.
|
|
func (a *App) editIP(w http.ResponseWriter, r *http.Request) {
|
|
rec, ok := a.ipWithAccess(w, r)
|
|
if !ok {
|
|
return
|
|
}
|
|
id := rec.ID
|
|
domains, _ := a.accessibleDomains(r)
|
|
|
|
ip := r.FormValue("ip_address")
|
|
domainID := int64(atoi(r.FormValue("domain_id")))
|
|
storeMessage := r.FormValue("store_message_content") == "on"
|
|
|
|
if net.ParseIP(ip).To4() == nil || domainID == 0 {
|
|
setFlash(w, "error", "A valid IPv4 address and domain are required")
|
|
a.render(w, r, "edit_ip.html", M{"active": "ips", "ip_record": rec, "domains": domains})
|
|
return
|
|
}
|
|
if !requireDomainAccess(w, r, domainID) {
|
|
return
|
|
}
|
|
if exists, _ := a.DB.IPPairExists(ip, domainID, id); exists {
|
|
setFlash(w, "error", "This IP is already whitelisted for this domain")
|
|
a.render(w, r, "edit_ip.html", M{"active": "ips", "ip_record": rec, "domains": domains})
|
|
return
|
|
}
|
|
if err := a.DB.UpdateWhitelistedIP(id, ip, domainID, storeMessage); err != nil {
|
|
setFlash(w, "error", "Error updating IP")
|
|
http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
|
|
return
|
|
}
|
|
setFlash(w, "success", "IP whitelist entry updated successfully")
|
|
http.Redirect(w, r, Prefix+"/ips", http.StatusFound)
|
|
}
|