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", tenantHandler.ListAll)
|
||||
mux.HandleFunc("/api/admin/agencies/", agencyHandler.HandleAgency)
|
||||
mux.HandleFunc("/api/tenant/check", tenantHandler.CheckExists)
|
||||
|
||||
// Client registration (ADMIN_AGENCIA only - requires auth)
|
||||
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")
|
||||
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()
|
||||
}
|
||||
|
||||
// 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
|
||||
func (s *TenantService) Delete(id uuid.UUID) error {
|
||||
if err := s.tenantRepo.Delete(id); err != nil {
|
||||
|
||||
@@ -14,7 +14,23 @@ export function middleware(request: NextRequest) {
|
||||
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.
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user