294 lines
10 KiB
Python
294 lines
10 KiB
Python
|
|
"""
|
|||
|
|
DNS routes - Yeni akış ile CF hesap seçimi, NS kontrolü, DNS yönetimi
|
|||
|
|
"""
|
|||
|
|
from flask import Blueprint, request, jsonify
|
|||
|
|
from datetime import datetime
|
|||
|
|
from app.models.domain import db, CloudflareAccount, Domain
|
|||
|
|
from app.services.cloudflare_service import CloudflareService
|
|||
|
|
from app.services.nameserver_service import NameserverService
|
|||
|
|
from app.services.auth_service import token_required
|
|||
|
|
import hashlib
|
|||
|
|
|
|||
|
|
dns_bp = Blueprint('dns', __name__, url_prefix='/api/dns')
|
|||
|
|
|
|||
|
|
|
|||
|
|
def select_lb_ip(domain: str, lb_ips: list) -> str:
|
|||
|
|
"""Domain için load balancer IP seç (hash-based)"""
|
|||
|
|
hash_value = int(hashlib.md5(domain.encode()).hexdigest(), 16)
|
|||
|
|
index = hash_value % len(lb_ips)
|
|||
|
|
return lb_ips[index]
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dns_bp.route('/check-nameservers', methods=['POST'])
|
|||
|
|
def check_nameservers():
|
|||
|
|
"""Domain'in nameserver'larını kontrol et"""
|
|||
|
|
try:
|
|||
|
|
data = request.json
|
|||
|
|
domain = data.get('domain')
|
|||
|
|
|
|||
|
|
if not domain:
|
|||
|
|
return jsonify({"error": "domain gerekli"}), 400
|
|||
|
|
|
|||
|
|
# NS kontrolü yap
|
|||
|
|
result = NameserverService.check_cloudflare_nameservers(domain)
|
|||
|
|
|
|||
|
|
return jsonify(result)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": f"NS kontrolü sırasında hata: {str(e)}"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dns_bp.route('/get-ns-instructions', methods=['POST'])
|
|||
|
|
def get_ns_instructions():
|
|||
|
|
"""NS yönlendirme talimatlarını al"""
|
|||
|
|
try:
|
|||
|
|
data = request.json
|
|||
|
|
domain = data.get('domain')
|
|||
|
|
zone_id = data.get('zone_id')
|
|||
|
|
api_token = data.get('api_token')
|
|||
|
|
|
|||
|
|
if not all([domain, zone_id, api_token]):
|
|||
|
|
return jsonify({"error": "domain, zone_id ve api_token gerekli"}), 400
|
|||
|
|
|
|||
|
|
# Mevcut NS'leri al
|
|||
|
|
current_ns = NameserverService.get_current_nameservers(domain)
|
|||
|
|
|
|||
|
|
# Cloudflare zone NS'lerini al
|
|||
|
|
cf_ns = NameserverService.get_cloudflare_zone_nameservers(zone_id, api_token)
|
|||
|
|
|
|||
|
|
if cf_ns["status"] == "error":
|
|||
|
|
return jsonify(cf_ns), 400
|
|||
|
|
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "success",
|
|||
|
|
"domain": domain,
|
|||
|
|
"current_nameservers": current_ns.get("nameservers", []),
|
|||
|
|
"cloudflare_nameservers": cf_ns["nameservers"],
|
|||
|
|
"instructions": [
|
|||
|
|
"1. Domain sağlayıcınızın (GoDaddy, Namecheap, vb.) kontrol paneline giriş yapın",
|
|||
|
|
"2. Domain yönetimi veya DNS ayarları bölümüne gidin",
|
|||
|
|
"3. 'Nameservers' veya 'Name Servers' seçeneğini bulun",
|
|||
|
|
"4. 'Custom Nameservers' veya 'Use custom nameservers' seçeneğini seçin",
|
|||
|
|
f"5. Aşağıdaki Cloudflare nameserver'larını ekleyin:",
|
|||
|
|
*[f" - {ns}" for ns in cf_ns["nameservers"]],
|
|||
|
|
"6. Değişiklikleri kaydedin",
|
|||
|
|
"7. DNS propagation 24-48 saat sürebilir (genellikle 1-2 saat içinde tamamlanır)"
|
|||
|
|
]
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": f"NS talimatları alınırken hata: {str(e)}"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dns_bp.route('/validate-token', methods=['POST'])
|
|||
|
|
def validate_cf_token():
|
|||
|
|
"""Cloudflare API token doğrula (müşterinin kendi token'ı)"""
|
|||
|
|
try:
|
|||
|
|
data = request.json
|
|||
|
|
domain = data.get('domain')
|
|||
|
|
cf_token = data.get('cf_token')
|
|||
|
|
|
|||
|
|
if not domain or not cf_token:
|
|||
|
|
return jsonify({"error": "domain ve cf_token gerekli"}), 400
|
|||
|
|
|
|||
|
|
cf_service = CloudflareService(cf_token)
|
|||
|
|
result = cf_service.validate_token_and_get_zone(domain)
|
|||
|
|
|
|||
|
|
return jsonify(result)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": f"Token doğrulama hatası: {str(e)}"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dns_bp.route('/select-company-account', methods=['POST'])
|
|||
|
|
def select_company_account():
|
|||
|
|
"""Şirket CF hesabı seç ve zone oluştur/bul"""
|
|||
|
|
try:
|
|||
|
|
data = request.json
|
|||
|
|
domain = data.get('domain')
|
|||
|
|
cf_account_id = data.get('cf_account_id')
|
|||
|
|
|
|||
|
|
if not domain or not cf_account_id:
|
|||
|
|
return jsonify({"error": "domain ve cf_account_id gerekli"}), 400
|
|||
|
|
|
|||
|
|
# CF hesabını al
|
|||
|
|
cf_account = CloudflareAccount.query.get(cf_account_id)
|
|||
|
|
|
|||
|
|
if not cf_account or not cf_account.is_active:
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": "Cloudflare hesabı bulunamadı veya aktif değil"
|
|||
|
|
}), 404
|
|||
|
|
|
|||
|
|
# Hesap kapasitesi kontrolü
|
|||
|
|
if cf_account.current_domain_count >= cf_account.max_domains:
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": f"Bu hesap kapasitesi dolmuş ({cf_account.current_domain_count}/{cf_account.max_domains})"
|
|||
|
|
}), 400
|
|||
|
|
|
|||
|
|
# API token'ı al
|
|||
|
|
api_token = cf_account.get_api_token()
|
|||
|
|
|
|||
|
|
# Cloudflare'de zone var mı kontrol et
|
|||
|
|
cf_service = CloudflareService(api_token)
|
|||
|
|
result = cf_service.validate_token_and_get_zone(domain)
|
|||
|
|
|
|||
|
|
if result["status"] == "success":
|
|||
|
|
# Zone zaten var
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "success",
|
|||
|
|
"zone_exists": True,
|
|||
|
|
**result
|
|||
|
|
})
|
|||
|
|
else:
|
|||
|
|
# Zone yok, oluşturulması gerekiyor
|
|||
|
|
# TODO: Zone oluşturma fonksiyonu eklenecek
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "pending",
|
|||
|
|
"zone_exists": False,
|
|||
|
|
"message": "Zone bulunamadı. Cloudflare'de zone oluşturulması gerekiyor.",
|
|||
|
|
"cf_account": cf_account.to_dict(include_token=False)
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": f"Hesap seçimi sırasında hata: {str(e)}"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dns_bp.route('/preview-changes', methods=['POST'])
|
|||
|
|
@token_required
|
|||
|
|
def preview_changes(current_user):
|
|||
|
|
"""DNS değişiklik önizlemesi"""
|
|||
|
|
try:
|
|||
|
|
customer = current_user.customer
|
|||
|
|
if not customer:
|
|||
|
|
return jsonify({'error': 'Customer profile not found'}), 404
|
|||
|
|
|
|||
|
|
data = request.json
|
|||
|
|
domain = data.get('domain')
|
|||
|
|
zone_id = data.get('zone_id')
|
|||
|
|
cf_token = data.get('cf_token')
|
|||
|
|
lb_ips = data.get('lb_ips', ['176.96.129.77']) # Default server IP
|
|||
|
|
|
|||
|
|
if not all([domain, zone_id, cf_token]):
|
|||
|
|
return jsonify({"error": "domain, zone_id ve cf_token gerekli"}), 400
|
|||
|
|
|
|||
|
|
# Load balancer IP seç
|
|||
|
|
new_ip = select_lb_ip(domain, lb_ips)
|
|||
|
|
|
|||
|
|
cf_service = CloudflareService(cf_token)
|
|||
|
|
preview = cf_service.generate_dns_preview(domain, zone_id, new_ip)
|
|||
|
|
|
|||
|
|
return jsonify(preview)
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": f"Preview oluşturma hatası: {str(e)}"
|
|||
|
|
}), 500
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dns_bp.route('/apply-changes', methods=['POST'])
|
|||
|
|
@token_required
|
|||
|
|
def apply_changes(current_user):
|
|||
|
|
"""DNS değişikliklerini uygula ve domain'i kaydet"""
|
|||
|
|
try:
|
|||
|
|
customer = current_user.customer
|
|||
|
|
if not customer:
|
|||
|
|
return jsonify({'error': 'Customer profile not found'}), 404
|
|||
|
|
|
|||
|
|
data = request.json
|
|||
|
|
domain_name = data.get('domain')
|
|||
|
|
zone_id = data.get('zone_id')
|
|||
|
|
cf_token = data.get('cf_token')
|
|||
|
|
preview = data.get('preview')
|
|||
|
|
proxy_enabled = data.get('proxy_enabled', True)
|
|||
|
|
cf_account_id = data.get('cf_account_id')
|
|||
|
|
cf_account_type = data.get('cf_account_type', 'company')
|
|||
|
|
project_name = data.get('project_name')
|
|||
|
|
|
|||
|
|
if not all([domain_name, zone_id, cf_token, preview]):
|
|||
|
|
return jsonify({"error": "Eksik parametreler"}), 400
|
|||
|
|
|
|||
|
|
# Check domain limit
|
|||
|
|
current_count = Domain.query.filter_by(customer_id=customer.id).count()
|
|||
|
|
if current_count >= customer.max_domains:
|
|||
|
|
return jsonify({
|
|||
|
|
'error': f'Domain limit reached ({customer.max_domains})'
|
|||
|
|
}), 403
|
|||
|
|
|
|||
|
|
# Check if domain already exists
|
|||
|
|
existing = Domain.query.filter_by(domain_name=domain_name).first()
|
|||
|
|
if existing:
|
|||
|
|
return jsonify({'error': 'Domain already exists'}), 409
|
|||
|
|
|
|||
|
|
cf_service = CloudflareService(cf_token)
|
|||
|
|
|
|||
|
|
# DNS değişikliklerini uygula
|
|||
|
|
result = cf_service.apply_dns_changes(zone_id, preview, proxy_enabled)
|
|||
|
|
|
|||
|
|
if result["status"] == "success":
|
|||
|
|
# SSL yapılandır
|
|||
|
|
ssl_config = cf_service.configure_ssl(zone_id)
|
|||
|
|
|
|||
|
|
# Domain'i veritabanına kaydet
|
|||
|
|
domain_obj = Domain(
|
|||
|
|
domain_name=domain_name,
|
|||
|
|
customer_id=customer.id,
|
|||
|
|
created_by=current_user.id,
|
|||
|
|
project_name=project_name,
|
|||
|
|
use_cloudflare=True,
|
|||
|
|
cf_account_type=cf_account_type,
|
|||
|
|
cf_account_id=cf_account_id if cf_account_type == 'company' else None,
|
|||
|
|
cf_zone_id=zone_id,
|
|||
|
|
cf_proxy_enabled=proxy_enabled,
|
|||
|
|
lb_ip=preview.get("new_ip"),
|
|||
|
|
status="active",
|
|||
|
|
dns_configured=True,
|
|||
|
|
ssl_configured=len(ssl_config.get("errors", [])) == 0
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# If using own CF account, save encrypted token
|
|||
|
|
if cf_account_type == 'own':
|
|||
|
|
domain_obj.set_cf_api_token(cf_token)
|
|||
|
|
|
|||
|
|
db.session.add(domain_obj)
|
|||
|
|
|
|||
|
|
# Update CF account domain count if using company account
|
|||
|
|
if cf_account_type == 'company' and cf_account_id:
|
|||
|
|
cf_account = CloudflareAccount.query.get(cf_account_id)
|
|||
|
|
if cf_account:
|
|||
|
|
cf_account.current_domain_count += 1
|
|||
|
|
|
|||
|
|
db.session.commit()
|
|||
|
|
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "success",
|
|||
|
|
"dns_result": result,
|
|||
|
|
"ssl_config": ssl_config,
|
|||
|
|
"domain_id": domain_obj.id,
|
|||
|
|
"domain": domain_obj.to_dict()
|
|||
|
|
}), 201
|
|||
|
|
|
|||
|
|
return jsonify(result), 500
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
db.session.rollback()
|
|||
|
|
return jsonify({
|
|||
|
|
"status": "error",
|
|||
|
|
"message": f"DNS uygulama hatası: {str(e)}"
|
|||
|
|
}), 500
|
|||
|
|
|