feat: block unknown subdomains via tenant check
This commit is contained in:
@@ -92,6 +92,7 @@ func main() {
|
|||||||
mux.HandleFunc("/api/admin/agencies/register", agencyHandler.RegisterAgency)
|
mux.HandleFunc("/api/admin/agencies/register", agencyHandler.RegisterAgency)
|
||||||
mux.HandleFunc("/api/admin/agencies", tenantHandler.ListAll)
|
mux.HandleFunc("/api/admin/agencies", tenantHandler.ListAll)
|
||||||
mux.HandleFunc("/api/admin/agencies/", agencyHandler.HandleAgency)
|
mux.HandleFunc("/api/admin/agencies/", agencyHandler.HandleAgency)
|
||||||
|
mux.HandleFunc("/api/tenant/check", tenantHandler.CheckExists)
|
||||||
|
|
||||||
// Client registration (ADMIN_AGENCIA only - requires auth)
|
// Client registration (ADMIN_AGENCIA only - requires auth)
|
||||||
mux.Handle("/api/agencies/clients/register", authMiddleware(http.HandlerFunc(agencyHandler.RegisterClient)))
|
mux.Handle("/api/agencies/clients/register", authMiddleware(http.HandlerFunc(agencyHandler.RegisterClient)))
|
||||||
|
|||||||
@@ -40,3 +40,31 @@ func (h *TenantHandler) ListAll(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
json.NewEncoder(w).Encode(tenants)
|
json.NewEncoder(w).Encode(tenants)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckExists returns 200 if tenant exists by subdomain, otherwise 404
|
||||||
|
func (h *TenantHandler) CheckExists(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
subdomain := r.URL.Query().Get("subdomain")
|
||||||
|
if subdomain == "" {
|
||||||
|
http.Error(w, "subdomain is required", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tenant, err := h.tenantService.GetBySubdomain(subdomain)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tenant == nil {
|
||||||
|
http.NotFound(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
|
||||||
|
}
|
||||||
|
|||||||
@@ -79,6 +79,11 @@ func (s *TenantService) ListAll() ([]*domain.Tenant, error) {
|
|||||||
return s.tenantRepo.FindAll()
|
return s.tenantRepo.FindAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBySubdomain returns tenant by subdomain or nil
|
||||||
|
func (s *TenantService) GetBySubdomain(subdomain string) (*domain.Tenant, error) {
|
||||||
|
return s.tenantRepo.FindBySubdomain(subdomain)
|
||||||
|
}
|
||||||
|
|
||||||
// Delete removes a tenant by ID
|
// Delete removes a tenant by ID
|
||||||
func (s *TenantService) Delete(id uuid.UUID) error {
|
func (s *TenantService) Delete(id uuid.UUID) error {
|
||||||
if err := s.tenantRepo.Delete(id); err != nil {
|
if err := s.tenantRepo.Delete(id); err != nil {
|
||||||
|
|||||||
@@ -14,7 +14,23 @@ export function middleware(request: NextRequest) {
|
|||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Se for agência ({subdomain}.localhost) - rotas de tenant
|
// Se for agência ({subdomain}.localhost) - validar se existe
|
||||||
|
if (hostname.includes('.')) {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`http://backend:8080/api/tenant/check?subdomain=${subdomain}`);
|
||||||
|
if (res.status === 404) {
|
||||||
|
// Redireciona para o host base (sem subdomínio)
|
||||||
|
const baseHost = hostname.split('.').slice(1).join('.') || hostname;
|
||||||
|
const redirectUrl = new URL(url.toString());
|
||||||
|
redirectUrl.hostname = baseHost;
|
||||||
|
redirectUrl.pathname = '/';
|
||||||
|
return NextResponse.redirect(redirectUrl);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Em caso de erro de rede, não bloquear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Permitir /dashboard, /login, /clientes, etc.
|
// Permitir /dashboard, /login, /clientes, etc.
|
||||||
return NextResponse.next();
|
return NextResponse.next();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user