first commit
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user