mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-02-27 00:40:46 +01:00
Fix DNS: add A/AAAA for all panel domains and subdomains (no duplicates)
This commit is contained in:
@@ -1199,6 +1199,91 @@ class DNSManager:
|
||||
final_json = json.dumps({'status': 0, 'delete_status': 0, 'error_message': str(msg), 'deleted_records': []})
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def fixDNSRecordsCloudFlare(self, userID=None, data=None):
|
||||
"""Ensure all panel domains/subdomains for the zone have A (and AAAA if available) in CloudFlare. No duplicates."""
|
||||
try:
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
if ACLManager.currentContextPermission(currentACL, 'addDeleteRecords') == 0:
|
||||
return ACLManager.loadErrorJson('fix_status', 0)
|
||||
zone_domain = data.get('selectedZone', '').strip()
|
||||
if not zone_domain:
|
||||
final_json = json.dumps({'status': 0, 'fix_status': 0, 'error_message': 'Zone is required.', 'added': 0, 'skipped': 0})
|
||||
return HttpResponse(final_json)
|
||||
admin = Administrator.objects.get(pk=userID)
|
||||
self.admin = admin
|
||||
if ACLManager.checkOwnershipZone(zone_domain, admin, currentACL) != 1:
|
||||
return ACLManager.loadErrorJson()
|
||||
valid_hostnames = self._get_valid_hostnames_for_zone(zone_domain)
|
||||
if not valid_hostnames:
|
||||
final_json = json.dumps({'status': 1, 'fix_status': 1, 'error_message': '', 'added': 0, 'skipped': 0})
|
||||
return HttpResponse(final_json)
|
||||
self.loadCFKeys()
|
||||
params = {'name': zone_domain, 'per_page': 50}
|
||||
cf = CloudFlare.CloudFlare(email=self.email, token=self.key)
|
||||
zones = cf.zones.get(params=params)
|
||||
if not zones:
|
||||
final_json = json.dumps({'status': 0, 'fix_status': 0, 'error_message': 'Zone not found.', 'added': 0, 'skipped': 0})
|
||||
return HttpResponse(final_json)
|
||||
zone_id = sorted(zones, key=lambda v: v['name'])[0]['id']
|
||||
existing = set()
|
||||
page = 1
|
||||
per_page = 100
|
||||
while True:
|
||||
try:
|
||||
dns_records = cf.zones.dns_records.get(zone_id, params={'per_page': per_page, 'page': page})
|
||||
except BaseException as e:
|
||||
final_json = json.dumps({'status': 0, 'fix_status': 0, 'error_message': str(e), 'added': 0, 'skipped': 0})
|
||||
return HttpResponse(final_json)
|
||||
if not dns_records:
|
||||
break
|
||||
for rec in dns_records:
|
||||
n = (rec.get('name') or '').lower().rstrip('.')
|
||||
t = (rec.get('type') or '').strip().upper()
|
||||
if n and t in ('A', 'AAAA', 'CNAME'):
|
||||
existing.add((n, t))
|
||||
if len(dns_records) < per_page:
|
||||
break
|
||||
page += 1
|
||||
server_ip = None
|
||||
try:
|
||||
server_ip = ACLManager.GetServerIP()
|
||||
except Exception:
|
||||
pass
|
||||
server_ipv6 = None
|
||||
try:
|
||||
server_ipv6 = ACLManager.GetServerIPv6()
|
||||
except Exception:
|
||||
pass
|
||||
ttl = 3600
|
||||
added = 0
|
||||
skipped = 0
|
||||
for hostname in valid_hostnames:
|
||||
name_lower = hostname.lower().rstrip('.')
|
||||
if (name_lower, 'A') not in existing and server_ip:
|
||||
try:
|
||||
DNS.createDNSRecordCloudFlare(cf, zone_id, hostname, 'A', server_ip, 0, ttl)
|
||||
existing.add((name_lower, 'A'))
|
||||
added += 1
|
||||
except BaseException as e:
|
||||
final_json = json.dumps({'status': 0, 'fix_status': 0, 'error_message': str(e), 'added': added, 'skipped': skipped})
|
||||
return HttpResponse(final_json)
|
||||
elif (name_lower, 'A') in existing:
|
||||
skipped += 1
|
||||
if server_ipv6 and (name_lower, 'AAAA') not in existing:
|
||||
try:
|
||||
DNS.createDNSRecordCloudFlare(cf, zone_id, hostname, 'AAAA', server_ipv6, 0, ttl)
|
||||
existing.add((name_lower, 'AAAA'))
|
||||
added += 1
|
||||
except BaseException as e:
|
||||
pass
|
||||
elif (name_lower, 'AAAA') in existing:
|
||||
skipped += 1
|
||||
final_json = json.dumps({'status': 1, 'fix_status': 1, 'error_message': '', 'added': added, 'skipped': skipped}, default=str)
|
||||
return HttpResponse(final_json)
|
||||
except BaseException as msg:
|
||||
final_json = json.dumps({'status': 0, 'fix_status': 0, 'error_message': str(msg), 'added': 0, 'skipped': 0})
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def updateDNSRecordCloudFlare(self, userID=None, data=None):
|
||||
"""Update an existing CloudFlare DNS record (name, type, ttl, content, priority, proxied)."""
|
||||
try:
|
||||
|
||||
@@ -860,6 +860,7 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
$scope.staleRecords = [];
|
||||
$scope.staleModalVisible = false;
|
||||
$scope.staleLoading = false;
|
||||
$scope.fixDNSLoading = false;
|
||||
|
||||
// Hide records boxes
|
||||
$(".aaaaRecord").hide();
|
||||
@@ -1355,6 +1356,29 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
$scope.staleRecords = [];
|
||||
};
|
||||
|
||||
$scope.fixDNS = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) return;
|
||||
$scope.fixDNSLoading = true;
|
||||
url = '/dns/fixDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
$scope.fixDNSLoading = false;
|
||||
if (response.data.fix_status === 1) {
|
||||
populateCurrentRecords();
|
||||
var msg = response.data.added + ' record(s) added.';
|
||||
if (response.data.skipped) msg += ' ' + response.data.skipped + ' already present.';
|
||||
new PNotify({ title: 'Fix DNS done', text: msg, type: 'success' });
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Fix DNS failed', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
$scope.fixDNSLoading = false;
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeStaleRecords = function () {
|
||||
if (!$scope.staleRecords || $scope.staleRecords.length === 0) return;
|
||||
var zone = $scope.selectedZone;
|
||||
|
||||
@@ -976,6 +976,9 @@
|
||||
<button type="button" ng-click="checkStaleRecords()" class="btn-secondary" ng-disabled="staleLoading" title="{% trans 'Find DNS records for subdomains that no longer exist in the panel' %}">
|
||||
<i class="fas fa-broom"></i> {% trans "Check orphan DNS" %}
|
||||
</button>
|
||||
<button type="button" ng-click="fixDNS()" class="btn-primary" ng-disabled="fixDNSLoading" title="{% trans 'Add A/AAAA records for all domains and subdomains in the panel; skip if already present' %}">
|
||||
<i class="fas fa-wrench"></i> {% trans "Fix DNS" %}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dns-search-wrap mb-3" ng-if="!loadingRecords && records.length > 0">
|
||||
|
||||
@@ -35,4 +35,5 @@ urlpatterns = [
|
||||
re_path(r'^importDNSRecordsCloudFlare$', views.importDNSRecordsCloudFlare, name='importDNSRecordsCloudFlare'),
|
||||
re_path(r'^getStaleDNSRecordsCloudFlare$', views.getStaleDNSRecordsCloudFlare, name='getStaleDNSRecordsCloudFlare'),
|
||||
re_path(r'^removeStaleDNSRecordsCloudFlare$', views.removeStaleDNSRecordsCloudFlare, name='removeStaleDNSRecordsCloudFlare'),
|
||||
re_path(r'^fixDNSRecordsCloudFlare$', views.fixDNSRecordsCloudFlare, name='fixDNSRecordsCloudFlare'),
|
||||
]
|
||||
|
||||
@@ -422,3 +422,12 @@ def removeStaleDNSRecordsCloudFlare(request):
|
||||
return dm.removeStaleDNSRecordsCloudFlare(userID, json.loads(request.body or '{}'))
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
|
||||
def fixDNSRecordsCloudFlare(request):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
dm = DNSManager()
|
||||
return dm.fixDNSRecordsCloudFlare(userID, json.loads(request.body or '{}'))
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
@@ -850,6 +850,7 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
$scope.staleRecords = [];
|
||||
$scope.staleModalVisible = false;
|
||||
$scope.staleLoading = false;
|
||||
$scope.fixDNSLoading = false;
|
||||
$scope.showEditModal = false;
|
||||
$scope.editRecord = {};
|
||||
|
||||
@@ -1378,6 +1379,29 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
$scope.staleRecords = [];
|
||||
};
|
||||
|
||||
$scope.fixDNS = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) return;
|
||||
$scope.fixDNSLoading = true;
|
||||
url = '/dns/fixDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
$scope.fixDNSLoading = false;
|
||||
if (response.data.fix_status === 1) {
|
||||
populateCurrentRecords();
|
||||
var msg = response.data.added + ' record(s) added.';
|
||||
if (response.data.skipped) msg += ' ' + response.data.skipped + ' already present.';
|
||||
new PNotify({ title: 'Fix DNS done', text: msg, type: 'success' });
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Fix DNS failed', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
$scope.fixDNSLoading = false;
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeStaleRecords = function () {
|
||||
if (!$scope.staleRecords || $scope.staleRecords.length === 0) return;
|
||||
var zone = $scope.selectedZone;
|
||||
|
||||
@@ -851,6 +851,7 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
$scope.staleRecords = [];
|
||||
$scope.staleModalVisible = false;
|
||||
$scope.staleLoading = false;
|
||||
$scope.fixDNSLoading = false;
|
||||
$scope.showEditModal = false;
|
||||
$scope.editRecord = {};
|
||||
|
||||
@@ -1383,6 +1384,29 @@ app.controller('addModifyDNSRecordsCloudFlare', function ($scope, $http, $window
|
||||
$scope.staleRecords = [];
|
||||
};
|
||||
|
||||
$scope.fixDNS = function () {
|
||||
var zone = $scope.selectedZone;
|
||||
if (!zone) return;
|
||||
$scope.fixDNSLoading = true;
|
||||
url = '/dns/fixDNSRecordsCloudFlare';
|
||||
var data = { selectedZone: zone };
|
||||
var config = { headers: { 'X-CSRFToken': getCookie('csrftoken') } };
|
||||
$http.post(url, data, config).then(function (response) {
|
||||
$scope.fixDNSLoading = false;
|
||||
if (response.data.fix_status === 1) {
|
||||
populateCurrentRecords();
|
||||
var msg = response.data.added + ' record(s) added.';
|
||||
if (response.data.skipped) msg += ' ' + response.data.skipped + ' already present.';
|
||||
new PNotify({ title: 'Fix DNS done', text: msg, type: 'success' });
|
||||
} else {
|
||||
new PNotify({ title: 'Error', text: response.data.error_message || 'Fix DNS failed', type: 'error' });
|
||||
}
|
||||
}, function () {
|
||||
$scope.fixDNSLoading = false;
|
||||
new PNotify({ title: 'Error', text: 'Could not connect to server.', type: 'error' });
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeStaleRecords = function () {
|
||||
if (!$scope.staleRecords || $scope.staleRecords.length === 0) return;
|
||||
var zone = $scope.selectedZone;
|
||||
|
||||
Reference in New Issue
Block a user