feat: geo-restriction via Cloudflare WAF custom rules
Add country-based access control managed through the Settings page.
Global allow-list with per-app overrides, searchable country selector,
automatic sync to Cloudflare WAF on settings change / deploy / remove,
plus periodic 6-hour verification.
New package: internal/cloudflare/ (client, zone, waf, countries, geosync)
New API: /api/geo/* (6 endpoints) + /api/stacks/{name}/geo/override
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -478,6 +478,22 @@ func (s *Server) appDetailHandler(w http.ResponseWriter, r *http.Request, slug s
|
||||
data["HasOptionalConfig"] = found.Meta.HasOptionalConfig()
|
||||
data["EffectiveSubdomain"] = effectiveSubdomain
|
||||
|
||||
// Geo-restriction per-app data
|
||||
geo := s.settings.GetGeoRestriction()
|
||||
if geo != nil && geo.Enabled && s.cfg.Infrastructure.CFAPIToken != "" {
|
||||
data["GeoGlobalEnabled"] = true
|
||||
data["GeoGlobalCountries"] = geo.AllowedCountries
|
||||
if ov, ok := geo.AppOverrides[found.Name]; ok {
|
||||
data["GeoAppOverride"] = true
|
||||
data["GeoAppOverrideCountries"] = ov.AllowedCountries
|
||||
} else {
|
||||
data["GeoAppOverrideCountries"] = []string{}
|
||||
}
|
||||
} else {
|
||||
data["GeoGlobalCountries"] = []string{}
|
||||
data["GeoAppOverrideCountries"] = []string{}
|
||||
}
|
||||
|
||||
s.executeTemplate(w, r, "app_info", data)
|
||||
}
|
||||
|
||||
@@ -1084,6 +1100,33 @@ func (s *Server) settingsData() map[string]interface{} {
|
||||
data["SupportEmail"] = "support@felhom.eu"
|
||||
data["SupportURL"] = "https://felhom.eu/kapcsolat"
|
||||
|
||||
// Geo-restriction data
|
||||
data["CFConfigured"] = s.cfg.Infrastructure.CFAPIToken != ""
|
||||
geo := s.settings.GetGeoRestriction()
|
||||
if geo != nil {
|
||||
data["GeoEnabled"] = geo.Enabled
|
||||
data["GeoAllowedCountries"] = geo.AllowedCountries
|
||||
data["GeoAppOverrides"] = geo.AppOverrides
|
||||
data["GeoLastSync"] = geo.LastSync
|
||||
data["GeoLastError"] = geo.LastSyncError
|
||||
} else {
|
||||
data["GeoEnabled"] = false
|
||||
data["GeoAllowedCountries"] = []string{"HU"}
|
||||
data["GeoAppOverrides"] = map[string]interface{}{}
|
||||
}
|
||||
// Deployed apps for per-app override selector
|
||||
var deployedApps []map[string]string
|
||||
for _, stack := range s.stackMgr.GetStacks() {
|
||||
if !stack.Deployed || s.cfg.IsProtectedStack(stack.Name) {
|
||||
continue
|
||||
}
|
||||
deployedApps = append(deployedApps, map[string]string{
|
||||
"Name": stack.Name,
|
||||
"Display": stack.Meta.DisplayName,
|
||||
})
|
||||
}
|
||||
data["DeployedApps"] = deployedApps
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user