mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-11-08 14:40:27 +00:00
Merge updates from master branch
This commit is contained in:
commit
fba93a57e1
@ -7,6 +7,10 @@ app = Flask(__name__)
|
|||||||
app.config.from_object('config')
|
app.config.from_object('config')
|
||||||
app.wsgi_app = ProxyFix(app.wsgi_app)
|
app.wsgi_app = ProxyFix(app.wsgi_app)
|
||||||
|
|
||||||
|
#### CONFIGURE LOGGER ####
|
||||||
|
from app.lib.log import logger
|
||||||
|
logging = logger('powerdns-admin', app.config['LOG_LEVEL'], app.config['LOG_FILE']).config()
|
||||||
|
|
||||||
login_manager = LoginManager()
|
login_manager = LoginManager()
|
||||||
login_manager.init_app(app)
|
login_manager.init_app(app)
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
@ -130,7 +130,7 @@ def display_record_name(data):
|
|||||||
if record_name == domain_name:
|
if record_name == domain_name:
|
||||||
return '@'
|
return '@'
|
||||||
else:
|
else:
|
||||||
return record_name.replace('.'+domain_name, '')
|
return re.sub('\.{}$'.format(domain_name), '', record_name)
|
||||||
|
|
||||||
|
|
||||||
def display_master_name(data):
|
def display_master_name(data):
|
||||||
@ -196,6 +196,9 @@ def email_to_gravatar_url(email="", size=100):
|
|||||||
"""
|
"""
|
||||||
AD doesn't necessarily have email
|
AD doesn't necessarily have email
|
||||||
"""
|
"""
|
||||||
|
if email is None:
|
||||||
|
email = ""
|
||||||
|
|
||||||
hash_string = hashlib.md5(email.encode('utf-8')).hexdigest()
|
hash_string = hashlib.md5(email.encode('utf-8')).hexdigest()
|
||||||
return "https://s.gravatar.com/avatar/{0}?s={1}".format(hash_string, size)
|
return "https://s.gravatar.com/avatar/{0}?s={1}".format(hash_string, size)
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import pyotp
|
|||||||
import re
|
import re
|
||||||
import dns.reversename
|
import dns.reversename
|
||||||
import sys
|
import sys
|
||||||
|
import logging as logger
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
@ -19,10 +20,8 @@ from flask_login import AnonymousUserMixin
|
|||||||
|
|
||||||
from app import app, db
|
from app import app, db
|
||||||
from app.lib import utils
|
from app.lib import utils
|
||||||
from app.lib.log import logger
|
|
||||||
|
|
||||||
# LOG CONFIGS
|
logging = logger.getLogger(__name__)
|
||||||
logging = logger('MODEL', app.config['LOG_LEVEL'], app.config['LOG_FILE']).config()
|
|
||||||
|
|
||||||
if 'LDAP_TYPE' in app.config.keys():
|
if 'LDAP_TYPE' in app.config.keys():
|
||||||
LDAP_URI = app.config['LDAP_URI']
|
LDAP_URI = app.config['LDAP_URI']
|
||||||
@ -135,6 +134,9 @@ class User(db.Model):
|
|||||||
def get_hashed_password(self, plain_text_password=None):
|
def get_hashed_password(self, plain_text_password=None):
|
||||||
# Hash a password for the first time
|
# Hash a password for the first time
|
||||||
# (Using bcrypt, the salt is saved into the hash itself)
|
# (Using bcrypt, the salt is saved into the hash itself)
|
||||||
|
if plain_text_password == None:
|
||||||
|
return plain_text_password
|
||||||
|
|
||||||
pw = plain_text_password if plain_text_password else self.plain_text_password
|
pw = plain_text_password if plain_text_password else self.plain_text_password
|
||||||
return bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt())
|
return bcrypt.hashpw(pw.encode('utf-8'), bcrypt.gensalt())
|
||||||
|
|
||||||
@ -316,6 +318,9 @@ class User(db.Model):
|
|||||||
|
|
||||||
self.password = self.get_hashed_password(self.plain_text_password)
|
self.password = self.get_hashed_password(self.plain_text_password)
|
||||||
|
|
||||||
|
if self.password:
|
||||||
|
self.password = self.password.decode("utf-8")
|
||||||
|
|
||||||
db.session.add(self)
|
db.session.add(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return {'status': True, 'msg': 'Created user successfully'}
|
return {'status': True, 'msg': 'Created user successfully'}
|
||||||
@ -335,7 +340,9 @@ class User(db.Model):
|
|||||||
user.password = self.get_hashed_password(self.plain_text_password) if self.plain_text_password else user.password
|
user.password = self.get_hashed_password(self.plain_text_password) if self.plain_text_password else user.password
|
||||||
user.avatar = self.avatar if self.avatar else user.avatar
|
user.avatar = self.avatar if self.avatar else user.avatar
|
||||||
|
|
||||||
user.otp_secret = ""
|
if enable_otp is not None:
|
||||||
|
user.otp_secret = ""
|
||||||
|
|
||||||
if enable_otp == True:
|
if enable_otp == True:
|
||||||
# generate the opt secret key
|
# generate the opt secret key
|
||||||
user.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8')
|
user.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8')
|
||||||
@ -502,24 +509,18 @@ class Domain(db.Model):
|
|||||||
logging.error('Can not create setting {0} for domain {1}. {2}'.format(setting, self.name, e))
|
logging.error('Can not create setting {0} for domain {1}. {2}'.format(setting, self.name, e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_domain_info(self, domain_name):
|
||||||
|
"""
|
||||||
|
Get all domains which has in PowerDNS
|
||||||
|
"""
|
||||||
|
headers = {}
|
||||||
|
headers['X-API-Key'] = PDNS_API_KEY
|
||||||
|
jdata = utils.fetch_json(urljoin(PDNS_STATS_URL, API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain_name)), headers=headers)
|
||||||
|
return jdata
|
||||||
|
|
||||||
def get_domains(self):
|
def get_domains(self):
|
||||||
"""
|
"""
|
||||||
Get all domains which has in PowerDNS
|
Get all domains which has in PowerDNS
|
||||||
jdata example:
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": "example.org.",
|
|
||||||
"url": "/servers/localhost/zones/example.org.",
|
|
||||||
"name": "example.org",
|
|
||||||
"kind": "Native",
|
|
||||||
"dnssec": false,
|
|
||||||
"account": "",
|
|
||||||
"masters": [],
|
|
||||||
"serial": 2015101501,
|
|
||||||
"notified_serial": 0,
|
|
||||||
"last_check": 0
|
|
||||||
}
|
|
||||||
]
|
|
||||||
"""
|
"""
|
||||||
headers = {}
|
headers = {}
|
||||||
headers['X-API-Key'] = PDNS_API_KEY
|
headers['X-API-Key'] = PDNS_API_KEY
|
||||||
@ -878,6 +879,7 @@ class Domain(db.Model):
|
|||||||
else:
|
else:
|
||||||
return {'status': 'error', 'msg': 'This domain doesnot exist'}
|
return {'status': 'error', 'msg': 'This domain doesnot exist'}
|
||||||
|
|
||||||
|
|
||||||
class DomainUser(db.Model):
|
class DomainUser(db.Model):
|
||||||
__tablename__ = 'domain_user'
|
__tablename__ = 'domain_user'
|
||||||
id = db.Column(db.Integer, primary_key = True)
|
id = db.Column(db.Integer, primary_key = True)
|
||||||
@ -1175,6 +1177,7 @@ class Record(object):
|
|||||||
return {'status': 'error', 'msg': jdata2['error']}
|
return {'status': 'error', 'msg': jdata2['error']}
|
||||||
else:
|
else:
|
||||||
self.auto_ptr(domain, new_records, deleted_records)
|
self.auto_ptr(domain, new_records, deleted_records)
|
||||||
|
self.update_db_serial(domain)
|
||||||
logging.info('Record was applied successfully.')
|
logging.info('Record was applied successfully.')
|
||||||
return {'status': 'ok', 'msg': 'Record was applied successfully'}
|
return {'status': 'ok', 'msg': 'Record was applied successfully'}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -1327,6 +1330,20 @@ class Record(object):
|
|||||||
logging.error("Cannot add record {0}/{1}/{2} to domain {3}. DETAIL: {4}".format(self.name, self.type, self.data, domain, e))
|
logging.error("Cannot add record {0}/{1}/{2} to domain {3}. DETAIL: {4}".format(self.name, self.type, self.data, domain, e))
|
||||||
return {'status': 'error', 'msg': 'There was something wrong, please contact administrator'}
|
return {'status': 'error', 'msg': 'There was something wrong, please contact administrator'}
|
||||||
|
|
||||||
|
def update_db_serial(self, domain):
|
||||||
|
headers = {}
|
||||||
|
headers['X-API-Key'] = PDNS_API_KEY
|
||||||
|
jdata = utils.fetch_json(urljoin(PDNS_STATS_URL, API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers, method='GET')
|
||||||
|
serial = jdata['serial']
|
||||||
|
|
||||||
|
domain = Domain.query.filter(Domain.name==domain).first()
|
||||||
|
if domain:
|
||||||
|
domain.serial = serial
|
||||||
|
db.session.commit()
|
||||||
|
return {'status': True, 'msg': 'Synced local serial for domain name {0}'.format(domain)}
|
||||||
|
else:
|
||||||
|
return {'status': False, 'msg': 'Could not find domain name {0} in local db'.format(domain)}
|
||||||
|
|
||||||
|
|
||||||
class Server(object):
|
class Server(object):
|
||||||
"""
|
"""
|
||||||
@ -1544,7 +1561,7 @@ class DomainTemplateRecord(db.Model):
|
|||||||
name = db.Column(db.String(255))
|
name = db.Column(db.String(255))
|
||||||
type = db.Column(db.String(64))
|
type = db.Column(db.String(64))
|
||||||
ttl = db.Column(db.Integer)
|
ttl = db.Column(db.Integer)
|
||||||
data = db.Column(db.String(255))
|
data = db.Column(db.Text)
|
||||||
status = db.Column(db.Boolean)
|
status = db.Column(db.Boolean)
|
||||||
template_id = db.Column(db.Integer, db.ForeignKey('domain_template.id'))
|
template_id = db.Column(db.Integer, db.ForeignKey('domain_template.id'))
|
||||||
template = db.relationship('DomainTemplate', back_populates='records')
|
template = db.relationship('DomainTemplate', back_populates='records')
|
||||||
|
@ -30,6 +30,37 @@ function applyChanges(data, url, showResult, refreshPage) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyRecordChanges(data, domain) {
|
||||||
|
var success = false;
|
||||||
|
$.ajax({
|
||||||
|
type : "POST",
|
||||||
|
url : $SCRIPT_ROOT + '/domain/' + domain + '/apply',
|
||||||
|
data : JSON.stringify(data),// now data come in this function
|
||||||
|
contentType : "application/json; charset=utf-8",
|
||||||
|
crossDomain : true,
|
||||||
|
dataType : "json",
|
||||||
|
success : function(data, status, jqXHR) {
|
||||||
|
// update Apply button value
|
||||||
|
$.getJSON($SCRIPT_ROOT + '/domain/' + domain + '/info', function(data) {
|
||||||
|
$(".button_apply_changes").val(data['serial']);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("Applied changes successfully.")
|
||||||
|
var modal = $("#modal_success");
|
||||||
|
modal.find('.modal-body p').text("Applied changes successfully");
|
||||||
|
modal.modal('show');
|
||||||
|
},
|
||||||
|
|
||||||
|
error : function(jqXHR, status) {
|
||||||
|
console.log(jqXHR);
|
||||||
|
var modal = $("#modal_error");
|
||||||
|
var responseJson = jQuery.parseJSON(jqXHR.responseText);
|
||||||
|
modal.find('.modal-body p').text(responseJson['msg']);
|
||||||
|
modal.modal('show');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getTableData(table) {
|
function getTableData(table) {
|
||||||
var rData = []
|
var rData = []
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@
|
|||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-flat btn-default pull-left"
|
<button type="button" class="btn btn-flat btn-default pull-left"
|
||||||
data-dismiss="modal">Close</button>
|
data-dismiss="modal">Close</button>
|
||||||
<button type="button" class="btn btn-flat btn-danger" onclick="applyChanges('', $SCRIPT_ROOT + '/admin/history');location.reload();">Clear History</button>
|
<button type="button" class="btn btn-flat btn-danger" onclick="applyChanges('', $SCRIPT_ROOT + '/admin/history', false, true);">Clear History</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.modal-content -->
|
<!-- /.modal-content -->
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<button type="button" class="btn btn-flat btn-primary pull-left button_add_record" id="{{ domain.name }}">
|
<button type="button" class="btn btn-flat btn-primary pull-left button_add_record" id="{{ domain.name }}">
|
||||||
Add Record <i class="fa fa-plus"></i>
|
Add Record <i class="fa fa-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-flat btn-primary pull-right button_apply_changes" id="{{ domain.name }}">
|
<button type="button" class="btn btn-flat btn-primary pull-right button_apply_changes" id="{{ domain.name }}" value="{{ domain.serial }}">
|
||||||
Apply Changes <i class="fa fa-floppy-o"></i>
|
Apply Changes <i class="fa fa-floppy-o"></i>
|
||||||
</button>
|
</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
@ -196,11 +196,14 @@
|
|||||||
var modal = $("#modal_apply_changes");
|
var modal = $("#modal_apply_changes");
|
||||||
var table = $("#tbl_records").DataTable();
|
var table = $("#tbl_records").DataTable();
|
||||||
var domain = $(this).prop('id');
|
var domain = $(this).prop('id');
|
||||||
|
var serial = $(".button_apply_changes").val();
|
||||||
var info = "Are you sure you want to apply your changes?";
|
var info = "Are you sure you want to apply your changes?";
|
||||||
modal.find('.modal-body p').text(info);
|
modal.find('.modal-body p').text(info);
|
||||||
modal.find('#button_apply_confirm').click(function() {
|
|
||||||
var data = getTableData(table);
|
// following unbind("click") is to avoid multiple times execution
|
||||||
applyChanges(data, $SCRIPT_ROOT + '/domain/' + domain + '/apply', true);
|
modal.find('#button_apply_confirm').unbind("click").click(function() {
|
||||||
|
var data = {'serial': serial, 'record': getTableData(table)};
|
||||||
|
applyRecordChanges(data, domain);
|
||||||
modal.modal('hide');
|
modal.modal('hide');
|
||||||
})
|
})
|
||||||
modal.modal('show');
|
modal.modal('show');
|
||||||
|
@ -32,7 +32,8 @@
|
|||||||
{% if not external_account %}<li><a href="#tabs-password" data-toggle="tab">Change
|
{% if not external_account %}<li><a href="#tabs-password" data-toggle="tab">Change
|
||||||
Password</a></li>
|
Password</a></li>
|
||||||
<li><a href="#tabs-authentication" data-toggle="tab">Authentication
|
<li><a href="#tabs-authentication" data-toggle="tab">Authentication
|
||||||
</a></li>{% endif %}>
|
</a></li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active" id="tabs-personal">
|
<div class="tab-pane active" id="tabs-personal">
|
||||||
|
128
app/views.py
128
app/views.py
@ -1,5 +1,6 @@
|
|||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
|
import logging as logger
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
import re
|
import re
|
||||||
@ -19,15 +20,13 @@ from werkzeug.security import gen_salt
|
|||||||
from .models import User, Domain, Record, Server, History, Anonymous, Setting, DomainSetting, DomainTemplate, DomainTemplateRecord
|
from .models import User, Domain, Record, Server, History, Anonymous, Setting, DomainSetting, DomainTemplate, DomainTemplateRecord
|
||||||
from app import app, login_manager, github, google
|
from app import app, login_manager, github, google
|
||||||
from app.lib import utils
|
from app.lib import utils
|
||||||
from app.lib.log import logger
|
|
||||||
from app.decorators import admin_role_required, can_access_domain
|
from app.decorators import admin_role_required, can_access_domain
|
||||||
|
|
||||||
if app.config['SAML_ENABLED']:
|
if app.config['SAML_ENABLED']:
|
||||||
from onelogin.saml2.auth import OneLogin_Saml2_Auth
|
from onelogin.saml2.auth import OneLogin_Saml2_Auth
|
||||||
from onelogin.saml2.utils import OneLogin_Saml2_Utils
|
from onelogin.saml2.utils import OneLogin_Saml2_Utils
|
||||||
|
|
||||||
# LOG CONFIG
|
logging = logger.getLogger(__name__)
|
||||||
logging = logger('MODEL', app.config['LOG_LEVEL'], app.config['LOG_FILE']).config()
|
|
||||||
|
|
||||||
# FILTERS
|
# FILTERS
|
||||||
jinja2.filters.FILTERS['display_record_name'] = utils.display_record_name
|
jinja2.filters.FILTERS['display_record_name'] = utils.display_record_name
|
||||||
@ -118,7 +117,7 @@ def login_via_authorization_header(request):
|
|||||||
if auth_header:
|
if auth_header:
|
||||||
auth_header = auth_header.replace('Basic ', '', 1)
|
auth_header = auth_header.replace('Basic ', '', 1)
|
||||||
try:
|
try:
|
||||||
auth_header = base64.b64decode(auth_header)
|
auth_header = str(base64.b64decode(auth_header), 'utf-8')
|
||||||
username,password = auth_header.split(":")
|
username,password = auth_header.split(":")
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
return None
|
return None
|
||||||
@ -312,12 +311,13 @@ def login():
|
|||||||
return redirect(url_for('index'))
|
return redirect(url_for('index'))
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
return render_template('login.html',
|
return render_template('login.html', github_enabled=GITHUB_ENABLE,
|
||||||
github_enabled=GITHUB_ENABLE,
|
google_enabled=GOOGLE_ENABLE,
|
||||||
google_enabled=GOOGLE_ENABLE,
|
saml_enabled=SAML_ENABLED,
|
||||||
saml_enabled=SAML_ENABLED,
|
ldap_enabled=LDAP_ENABLED,
|
||||||
ldap_enabled=LDAP_ENABLED, login_title=LOGIN_TITLE,
|
login_title=LOGIN_TITLE,
|
||||||
basic_enabled=BASIC_ENABLED, signup_enabled=SIGNUP_ENABLED)
|
basic_enabled=BASIC_ENABLED,
|
||||||
|
signup_enabled=SIGNUP_ENABLED)
|
||||||
|
|
||||||
# process login
|
# process login
|
||||||
username = request.form['username']
|
username = request.form['username']
|
||||||
@ -331,6 +331,9 @@ def login():
|
|||||||
email = request.form.get('email')
|
email = request.form.get('email')
|
||||||
rpassword = request.form.get('rpassword')
|
rpassword = request.form.get('rpassword')
|
||||||
|
|
||||||
|
if auth_method != 'LOCAL':
|
||||||
|
session['external_auth'] = True
|
||||||
|
|
||||||
if None in [firstname, lastname, email]:
|
if None in [firstname, lastname, email]:
|
||||||
#login case
|
#login case
|
||||||
remember_me = False
|
remember_me = False
|
||||||
@ -342,37 +345,46 @@ def login():
|
|||||||
try:
|
try:
|
||||||
auth = user.is_validate(method=auth_method)
|
auth = user.is_validate(method=auth_method)
|
||||||
if auth == False:
|
if auth == False:
|
||||||
return render_template('login.html', error='Invalid credentials', ldap_enabled=LDAP_ENABLED,
|
return render_template('login.html', error='Invalid credentials',
|
||||||
login_title=LOGIN_TITLE,
|
github_enabled=GITHUB_ENABLE,
|
||||||
basic_enabled=BASIC_ENABLED,
|
google_enabled=GOOGLE_ENABLE,
|
||||||
signup_enabled=SIGNUP_ENABLED,
|
saml_enabled=SAML_ENABLED,
|
||||||
github_enabled=GITHUB_ENABLE,
|
ldap_enabled=LDAP_ENABLED,
|
||||||
saml_enabled=SAML_ENABLED)
|
login_title=LOGIN_TITLE,
|
||||||
|
basic_enabled=BASIC_ENABLED,
|
||||||
|
signup_enabled=SIGNUP_ENABLED)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return render_template('login.html', error=e, ldap_enabled=LDAP_ENABLED, login_title=LOGIN_TITLE,
|
return render_template('login.html', error=e,
|
||||||
basic_enabled=BASIC_ENABLED,
|
github_enabled=GITHUB_ENABLE,
|
||||||
signup_enabled=SIGNUP_ENABLED,
|
google_enabled=GOOGLE_ENABLE,
|
||||||
github_enabled=GITHUB_ENABLE,
|
saml_enabled=SAML_ENABLED,
|
||||||
saml_enabled=SAML_ENABLED)
|
ldap_enabled=LDAP_ENABLED,
|
||||||
|
login_title=LOGIN_TITLE,
|
||||||
|
basic_enabled=BASIC_ENABLED,
|
||||||
|
signup_enabled=SIGNUP_ENABLED)
|
||||||
|
|
||||||
# check if user enabled OPT authentication
|
# check if user enabled OPT authentication
|
||||||
if user.otp_secret:
|
if user.otp_secret:
|
||||||
if otp_token:
|
if otp_token:
|
||||||
good_token = user.verify_totp(otp_token)
|
good_token = user.verify_totp(otp_token)
|
||||||
if not good_token:
|
if not good_token:
|
||||||
return render_template('login.html', error='Invalid credentials', ldap_enabled=LDAP_ENABLED,
|
return render_template('login.html', error='Invalid credentials',
|
||||||
login_title=LOGIN_TITLE,
|
github_enabled=GITHUB_ENABLE,
|
||||||
basic_enabled=BASIC_ENABLED,
|
google_enabled=GOOGLE_ENABLE,
|
||||||
signup_enabled=SIGNUP_ENABLED,
|
saml_enabled=SAML_ENABLED,
|
||||||
github_enabled=GITHUB_ENABLE,
|
ldap_enabled=LDAP_ENABLED,
|
||||||
saml_enabled=SAML_ENABLED)
|
login_title=LOGIN_TITLE,
|
||||||
|
basic_enabled=BASIC_ENABLED,
|
||||||
|
signup_enabled=SIGNUP_ENABLED)
|
||||||
else:
|
else:
|
||||||
return render_template('login.html', error='Token required', ldap_enabled=LDAP_ENABLED,
|
return render_template('login.html', error='Token required',
|
||||||
login_title=LOGIN_TITLE,
|
github_enabled=GITHUB_ENABLE,
|
||||||
basic_enabled=BASIC_ENABLED,
|
google_enabled=GOOGLE_ENABLE,
|
||||||
signup_enabled=SIGNUP_ENABLED,
|
saml_enabled=SAML_ENABLED,
|
||||||
github_enabled = GITHUB_ENABLE,
|
ldap_enabled=LDAP_ENABLED,
|
||||||
saml_enabled = SAML_ENABLED)
|
login_title=LOGIN_TITLE,
|
||||||
|
basic_enabled=BASIC_ENABLED,
|
||||||
|
signup_enabled=SIGNUP_ENABLED)
|
||||||
|
|
||||||
login_user(user, remember = remember_me)
|
login_user(user, remember = remember_me)
|
||||||
return redirect(request.args.get('next') or url_for('index'))
|
return redirect(request.args.get('next') or url_for('index'))
|
||||||
@ -389,9 +401,14 @@ def login():
|
|||||||
try:
|
try:
|
||||||
result = user.create_local_user()
|
result = user.create_local_user()
|
||||||
if result == True:
|
if result == True:
|
||||||
return render_template('login.html', username=username, password=password, ldap_enabled=LDAP_ENABLED,
|
return render_template('login.html', username=username, password=password,
|
||||||
login_title=LOGIN_TITLE, basic_enabled=BASIC_ENABLED, signup_enabled=SIGNUP_ENABLED,
|
github_enabled=GITHUB_ENABLE,
|
||||||
github_enabled=GITHUB_ENABLE,saml_enabled=SAML_ENABLED)
|
google_enabled=GOOGLE_ENABLE,
|
||||||
|
saml_enabled=SAML_ENABLED,
|
||||||
|
ldap_enabled=LDAP_ENABLED,
|
||||||
|
login_title=LOGIN_TITLE,
|
||||||
|
basic_enabled=BASIC_ENABLED,
|
||||||
|
signup_enabled=SIGNUP_ENABLED)
|
||||||
else:
|
else:
|
||||||
return render_template('register.html', error=result['msg'])
|
return render_template('register.html', error=result['msg'])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -523,7 +540,6 @@ def dashboard_domains():
|
|||||||
|
|
||||||
|
|
||||||
@app.route('/domain/<path:domain_name>', methods=['GET', 'POST'])
|
@app.route('/domain/<path:domain_name>', methods=['GET', 'POST'])
|
||||||
@app.route('/domain', methods=['GET', 'POST'])
|
|
||||||
@login_required
|
@login_required
|
||||||
@can_access_domain
|
@can_access_domain
|
||||||
def domain(domain_name):
|
def domain(domain_name):
|
||||||
@ -551,7 +567,7 @@ def domain(domain_name):
|
|||||||
if not re.search('ip6\.arpa|in-addr\.arpa$', domain_name):
|
if not re.search('ip6\.arpa|in-addr\.arpa$', domain_name):
|
||||||
editable_records = app.config['RECORDS_ALLOW_EDIT']
|
editable_records = app.config['RECORDS_ALLOW_EDIT']
|
||||||
else:
|
else:
|
||||||
editable_records = app.config['REVERSE_ALLOW_EDIT']
|
editable_records = app.config['REVERSE_RECORDS_ALLOW_EDIT']
|
||||||
return render_template('domain.html', domain=domain, records=records, editable_records=editable_records)
|
return render_template('domain.html', domain=domain, records=records, editable_records=editable_records)
|
||||||
else:
|
else:
|
||||||
for jr in jrecords:
|
for jr in jrecords:
|
||||||
@ -562,7 +578,7 @@ def domain(domain_name):
|
|||||||
editable_records = app.config['FORWARD_RECORDS_ALLOW_EDIT']
|
editable_records = app.config['FORWARD_RECORDS_ALLOW_EDIT']
|
||||||
else:
|
else:
|
||||||
editable_records = app.config['REVERSE_RECORDS_ALLOW_EDIT']
|
editable_records = app.config['REVERSE_RECORDS_ALLOW_EDIT']
|
||||||
return render_template('domain.html', domain=domain, records=records, editable_records=editable_records,pdns_version=app.config['PDNS_VERSION'])
|
return render_template('domain.html', domain=domain, records=records, editable_records=editable_records, pdns_version=app.config['PDNS_VERSION'])
|
||||||
|
|
||||||
|
|
||||||
@app.route('/admin/domain/add', methods=['GET', 'POST'])
|
@app.route('/admin/domain/add', methods=['GET', 'POST'])
|
||||||
@ -575,7 +591,6 @@ def domain_add():
|
|||||||
domain_name = request.form.getlist('domain_name')[0]
|
domain_name = request.form.getlist('domain_name')[0]
|
||||||
domain_type = request.form.getlist('radio_type')[0]
|
domain_type = request.form.getlist('radio_type')[0]
|
||||||
domain_template = request.form.getlist('domain_template')[0]
|
domain_template = request.form.getlist('domain_template')[0]
|
||||||
logging.info("Selected template ==== {0}".format(domain_template))
|
|
||||||
soa_edit_api = request.form.getlist('radio_type_soa_edit_api')[0]
|
soa_edit_api = request.form.getlist('radio_type_soa_edit_api')[0]
|
||||||
|
|
||||||
if ' ' in domain_name or not domain_name or not domain_type:
|
if ' ' in domain_name or not domain_name or not domain_type:
|
||||||
@ -698,11 +713,26 @@ def record_apply(domain_name):
|
|||||||
example jdata: {u'record_ttl': u'1800', u'record_type': u'CNAME', u'record_name': u'test4', u'record_status': u'Active', u'record_data': u'duykhanh.me'}
|
example jdata: {u'record_ttl': u'1800', u'record_type': u'CNAME', u'record_name': u'test4', u'record_status': u'Active', u'record_data': u'duykhanh.me'}
|
||||||
"""
|
"""
|
||||||
#TODO: filter removed records / name modified records.
|
#TODO: filter removed records / name modified records.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
jdata = request.json
|
jdata = request.json
|
||||||
|
|
||||||
|
submitted_serial = jdata['serial']
|
||||||
|
submitted_record = jdata['record']
|
||||||
|
|
||||||
|
domain = Domain.query.filter(Domain.name==domain_name).first()
|
||||||
|
|
||||||
|
logging.debug('Your submitted serial: {0}'.format(submitted_serial))
|
||||||
|
logging.debug('Current domain serial: {0}'.format(domain.serial))
|
||||||
|
|
||||||
|
if domain:
|
||||||
|
if int(submitted_serial) != domain.serial:
|
||||||
|
return make_response(jsonify( {'status': 'error', 'msg': 'The zone has been changed by another session or user. Please refresh this web page to load updated records.'} ), 500)
|
||||||
|
else:
|
||||||
|
return make_response(jsonify( {'status': 'error', 'msg': 'Domain name {0} does not exist'.format(domain_name)} ), 404)
|
||||||
|
|
||||||
r = Record()
|
r = Record()
|
||||||
result = r.apply(domain_name, jdata)
|
result = r.apply(domain_name, submitted_record)
|
||||||
if result['status'] == 'ok':
|
if result['status'] == 'ok':
|
||||||
history = History(msg='Apply record changes to domain {0}'.format(domain_name), detail=str(jdata), created_by=current_user.username)
|
history = History(msg='Apply record changes to domain {0}'.format(domain_name), detail=str(jdata), created_by=current_user.username)
|
||||||
history.add()
|
history.add()
|
||||||
@ -752,6 +782,15 @@ def record_delete(domain_name, record_name, record_type):
|
|||||||
return redirect(url_for('domain', domain_name=domain_name))
|
return redirect(url_for('domain', domain_name=domain_name))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/domain/<path:domain_name>/info', methods=['GET'])
|
||||||
|
@login_required
|
||||||
|
@can_access_domain
|
||||||
|
def domain_info(domain_name):
|
||||||
|
domain = Domain()
|
||||||
|
domain_info = domain.get_domain_info(domain_name)
|
||||||
|
return make_response(jsonify(domain_info), 200)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/domain/<path:domain_name>/dnssec', methods=['GET'])
|
@app.route('/domain/<path:domain_name>/dnssec', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
@can_access_domain
|
@can_access_domain
|
||||||
@ -898,17 +937,18 @@ def create_template_from_zone():
|
|||||||
|
|
||||||
if NEW_SCHEMA:
|
if NEW_SCHEMA:
|
||||||
for jr in jrecords:
|
for jr in jrecords:
|
||||||
name = '@' if jr['name'] == domain_name else jr['name']
|
|
||||||
if jr['type'] in app.config['RECORDS_ALLOW_EDIT']:
|
if jr['type'] in app.config['RECORDS_ALLOW_EDIT']:
|
||||||
|
name = '@' if jr['name'] == domain_name else re.sub('\.{}$'.format(domain_name), '', jr['name'])
|
||||||
for subrecord in jr['records']:
|
for subrecord in jr['records']:
|
||||||
|
|
||||||
record = DomainTemplateRecord(name=name, type=jr['type'], status=True if subrecord['disabled'] else False, ttl=jr['ttl'], data=subrecord['content'])
|
record = DomainTemplateRecord(name=name, type=jr['type'], status=True if subrecord['disabled'] else False, ttl=jr['ttl'], data=subrecord['content'])
|
||||||
records.append(record)
|
records.append(record)
|
||||||
else:
|
else:
|
||||||
for jr in jrecords:
|
for jr in jrecords:
|
||||||
if jr['type'] in app.config['RECORDS_ALLOW_EDIT']:
|
if jr['type'] in app.config['RECORDS_ALLOW_EDIT']:
|
||||||
|
name = '@' if jr['name'] == domain_name else re.sub('\.{}$'.format(domain_name), '', jr['name'])
|
||||||
record = DomainTemplateRecord(name=name, type=jr['type'], status=True if jr['disabled'] else False, ttl=jr['ttl'], data=jr['content'])
|
record = DomainTemplateRecord(name=name, type=jr['type'], status=True if jr['disabled'] else False, ttl=jr['ttl'], data=jr['content'])
|
||||||
records.append(record)
|
records.append(record)
|
||||||
|
|
||||||
result_records = t.replace_records(records)
|
result_records = t.replace_records(records)
|
||||||
|
|
||||||
if result_records['status'] == 'ok':
|
if result_records['status'] == 'ok':
|
||||||
@ -1150,7 +1190,7 @@ def admin_settings_edit(setting):
|
|||||||
@login_required
|
@login_required
|
||||||
def user_profile():
|
def user_profile():
|
||||||
external_account = False
|
external_account = False
|
||||||
if session.has_key('external_auth'):
|
if 'external_auth' in session:
|
||||||
external_account = session['external_auth']
|
external_account = session['external_auth']
|
||||||
if request.method == 'GET' or external_account:
|
if request.method == 'GET' or external_account:
|
||||||
return render_template('user_profile.html', external_account=external_account)
|
return render_template('user_profile.html', external_account=external_account)
|
||||||
|
@ -123,7 +123,7 @@ PDNS_VERSION = '4.1.1'
|
|||||||
# RECORDS ALLOWED TO EDIT
|
# RECORDS ALLOWED TO EDIT
|
||||||
RECORDS_ALLOW_EDIT = ['SOA', 'A', 'AAAA', 'CAA', 'CNAME', 'MX', 'PTR', 'SPF', 'SRV', 'TXT', 'LOC', 'NS', 'PTR']
|
RECORDS_ALLOW_EDIT = ['SOA', 'A', 'AAAA', 'CAA', 'CNAME', 'MX', 'PTR', 'SPF', 'SRV', 'TXT', 'LOC', 'NS', 'PTR']
|
||||||
FORWARD_RECORDS_ALLOW_EDIT = ['A', 'AAAA', 'CAA', 'CNAME', 'MX', 'PTR', 'SPF', 'SRV', 'TXT', 'LOC' 'NS']
|
FORWARD_RECORDS_ALLOW_EDIT = ['A', 'AAAA', 'CAA', 'CNAME', 'MX', 'PTR', 'SPF', 'SRV', 'TXT', 'LOC' 'NS']
|
||||||
REVERSE_RECORDS_ALLOW_EDIT = ['TXT', 'LOC', 'NS', 'PTR']
|
REVERSE_RECORDS_ALLOW_EDIT = ['SOA', 'TXT', 'LOC', 'NS', 'PTR']
|
||||||
|
|
||||||
# EXPERIMENTAL FEATURES
|
# EXPERIMENTAL FEATURES
|
||||||
PRETTY_IPV6_PTR = False
|
PRETTY_IPV6_PTR = False
|
||||||
|
@ -111,10 +111,9 @@ PDNS_API_KEY = os.environ.get('PDNS_API_KEY')
|
|||||||
PDNS_VERSION = '4.1.1'
|
PDNS_VERSION = '4.1.1'
|
||||||
|
|
||||||
# RECORDS ALLOWED TO EDIT
|
# RECORDS ALLOWED TO EDIT
|
||||||
RECORDS_ALLOW_EDIT = ['A', 'AAAA', 'CAA', 'CNAME', 'MX', 'PTR', 'SPF', 'SRV', 'TXT', 'NS']
|
RECORDS_ALLOW_EDIT = ['SOA', 'A', 'AAAA', 'CAA', 'CNAME', 'MX', 'PTR', 'SPF', 'SRV', 'TXT', 'LOC', 'NS', 'PTR']
|
||||||
|
FORWARD_RECORDS_ALLOW_EDIT = ['A', 'AAAA', 'CAA', 'CNAME', 'MX', 'PTR', 'SPF', 'SRV', 'TXT', 'LOC' 'NS']
|
||||||
# RECORDS ALLOWED TO EDIT FOR REVERSE DOMAINS
|
REVERSE_RECORDS_ALLOW_EDIT = ['SOA', 'TXT', 'LOC', 'NS', 'PTR']
|
||||||
REVERSE_ALLOW_EDIT = ['PTR', 'NS']
|
|
||||||
|
|
||||||
# EXPERIMENTAL FEATURES
|
# EXPERIMENTAL FEATURES
|
||||||
PRETTY_IPV6_PTR = False
|
PRETTY_IPV6_PTR = False
|
||||||
|
Loading…
Reference in New Issue
Block a user