diff --git a/.lgtm.yml b/.lgtm.yml new file mode 100644 index 0000000..a8c5b04 --- /dev/null +++ b/.lgtm.yml @@ -0,0 +1,10 @@ +extraction: + python: + python_setup: + version: 3 + index: + exclude: + - .git + - upload + - flask + - node_modules diff --git a/app/__init__.py b/app/__init__.py index b2425ce..00c510c 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -29,7 +29,7 @@ login_manager = LoginManager() login_manager.init_app(app) db = SQLAlchemy(app) # database migrate = Migrate(app, db) # flask-migrate -oauth = OAuth(app) # oauth +oauth_client = OAuth(app) # oauth if app.config.get('SAML_ENABLED') and app.config.get('SAML_ENCRYPT'): from app.lib import certutil diff --git a/app/decorators.py b/app/decorators.py index 673eea6..a1cfacf 100644 --- a/app/decorators.py +++ b/app/decorators.py @@ -1,11 +1,13 @@ from functools import wraps -from flask import g, request, redirect, url_for +from flask import g, redirect, url_for -from app import app -from app.models import Role, Setting +from app.models import Setting def admin_role_required(f): + """ + Grant access if user is in Administrator role + """ @wraps(f) def decorated_function(*args, **kwargs): if g.user.role.name != 'Administrator': @@ -14,10 +16,28 @@ def admin_role_required(f): return decorated_function -def can_access_domain(f): +def operator_role_required(f): + """ + Grant access if user is in Operator role or higher + """ @wraps(f) def decorated_function(*args, **kwargs): - if g.user.role.name != 'Administrator': + if g.user.role.name not in ['Administrator', 'Operator']: + return redirect(url_for('error', code=401)) + return f(*args, **kwargs) + return decorated_function + + +def can_access_domain(f): + """ + Grant access if: + - user is in Operator role or higher, or + - user is in granted Account, or + - user is in granted Domain + """ + @wraps(f) + def decorated_function(*args, **kwargs): + if g.user.role.name not in ['Administrator', 'Operator']: domain_name = kwargs.get('domain_name') user_domain = [d.name for d in g.user.get_domain()] @@ -29,10 +49,30 @@ def can_access_domain(f): def can_configure_dnssec(f): + """ + Grant access if: + - user is in Operator role or higher, or + - dnssec_admins_only is off + """ @wraps(f) def decorated_function(*args, **kwargs): - if g.user.role.name != 'Administrator' and Setting().get('dnssec_admins_only'): - return redirect(url_for('error', code=401)) + if g.user.role.name not in ['Administrator', 'Operator'] and Setting().get('dnssec_admins_only'): + return redirect(url_for('error', code=401)) + + return f(*args, **kwargs) + return decorated_function + + +def can_create_domain(f): + """ + Grant access if: + - user is in Operator role or higher, or + - allow_user_create_domain is on + """ + @wraps(f) + def decorated_function(*args, **kwargs): + if g.user.role.name not in ['Administrator', 'Operator'] and not Setting().get('allow_user_create_domain'): + return redirect(url_for('error', code=401)) return f(*args, **kwargs) return decorated_function diff --git a/app/lib/log.py b/app/lib/log.py index 87a186f..ea329ea 100644 --- a/app/lib/log.py +++ b/app/lib/log.py @@ -1,4 +1,3 @@ -import os import logging class logger(object): diff --git a/app/lib/utils.py b/app/lib/utils.py index 5899acd..881fddc 100644 --- a/app/lib/utils.py +++ b/app/lib/utils.py @@ -1,5 +1,4 @@ import re -import sys import json import requests import hashlib @@ -10,12 +9,10 @@ from urllib.parse import urlparse from datetime import datetime, timedelta from threading import Thread -from .certutil import * +from .certutil import KEY_FILE, CERT_FILE if app.config['SAML_ENABLED']: from onelogin.saml2.auth import OneLogin_Saml2_Auth - from onelogin.saml2.utils import OneLogin_Saml2_Utils - from onelogin.saml2.settings import OneLogin_Saml2_Settings from onelogin.saml2.idp_metadata_parser import OneLogin_Saml2_IdPMetadataParser idp_timestamp = datetime(1970, 1, 1) idp_data = None @@ -227,7 +224,7 @@ def prepare_flask_request(request): def init_saml_auth(req): own_url = '' - if req['https'] is 'on': + if req['https'] == 'on': own_url = 'https://' else: own_url = 'http://' @@ -285,3 +282,12 @@ def init_saml_auth(req): settings['organization']['en-US']['url'] = own_url auth = OneLogin_Saml2_Auth(req, settings) return auth + + +def display_setting_state(value): + if value == 1: + return "ON" + elif value == 0: + return "OFF" + else: + return "UNKNOWN" diff --git a/app/models.py b/app/models.py index be19fe9..63e4381 100644 --- a/app/models.py +++ b/app/models.py @@ -1,17 +1,16 @@ +import sys import os +import re import ldap import ldap.filter -import time import base64 import bcrypt import itertools import traceback import pyotp -import re import dns.reversename import dns.inet import dns.name -import sys import logging as logger from ast import literal_eval @@ -150,7 +149,7 @@ class User(db.Model): logging.error(e) logging.debug('baseDN: {0}'.format(baseDN)) logging.debug(traceback.format_exc()) - raise + def ldap_auth(self, ldap_username, password): try: @@ -165,6 +164,8 @@ class User(db.Model): """ Validate user credential """ + role_name = 'User' + if method == 'LOCAL': user_info = User.query.filter(User.username == self.username).first() @@ -179,12 +180,12 @@ class User(db.Model): return False if method == 'LDAP': - isadmin = False LDAP_TYPE = Setting().get('ldap_type') LDAP_BASE_DN = Setting().get('ldap_base_dn') LDAP_FILTER_BASIC = Setting().get('ldap_filter_basic') LDAP_FILTER_USERNAME = Setting().get('ldap_filter_username') LDAP_ADMIN_GROUP = Setting().get('ldap_admin_group') + LDAP_OPERATOR_GROUP = Setting().get('ldap_operator_group') LDAP_USER_GROUP = Setting().get('ldap_user_group') LDAP_GROUP_SECURITY_ENABLED = Setting().get('ldap_sg_enabled') @@ -206,24 +207,30 @@ class User(db.Model): try: if LDAP_TYPE == 'ldap': if (self.ldap_search(searchFilter, LDAP_ADMIN_GROUP)): - isadmin = True + role_name = 'Administrator' logging.info('User {0} is part of the "{1}" group that allows admin access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP)) + elif (self.ldap_search(searchFilter, LDAP_OPERATOR_GROUP)): + role_name = 'Operator' + logging.info('User {0} is part of the "{1}" group that allows operator access to PowerDNS-Admin'.format(self.username, LDAP_OPERATOR_GROUP)) elif (self.ldap_search(searchFilter, LDAP_USER_GROUP)): logging.info('User {0} is part of the "{1}" group that allows user access to PowerDNS-Admin'.format(self.username, LDAP_USER_GROUP)) else: - logging.error('User {0} is not part of the "{1}" or "{2}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_USER_GROUP)) + logging.error('User {0} is not part of the "{1}", "{2}" or "{3}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_OPERATOR_GROUP, LDAP_USER_GROUP)) return False elif LDAP_TYPE == 'ad': user_ldap_groups = [g.decode("utf-8") for g in ldap_result[0][0][1]['memberOf']] logging.debug('user_ldap_groups: {0}'.format(user_ldap_groups)) if (LDAP_ADMIN_GROUP in user_ldap_groups): - isadmin = True + role_name = 'Administrator' logging.info('User {0} is part of the "{1}" group that allows admin access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP)) + elif (LDAP_OPERATOR_GROUP in user_ldap_groups): + role_name = 'Operator' + logging.info('User {0} is part of the "{1}" group that allows operator access to PowerDNS-Admin'.format(self.username, LDAP_OPERATOR_GROUP)) elif (LDAP_USER_GROUP in user_ldap_groups): logging.info('User {0} is part of the "{1}" group that allows user access to PowerDNS-Admin'.format(self.username, LDAP_USER_GROUP)) else: - logging.error('User {0} is not part of the "{1}" or "{2}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_USER_GROUP)) + logging.error('User {0} is not part of the "{1}", "{2}" or "{3}" groups that allow access to PowerDNS-Admin'.format(self.username, LDAP_ADMIN_GROUP, LDAP_OPERATOR_GROUP, LDAP_USER_GROUP)) return False else: logging.error('Invalid LDAP type') @@ -261,21 +268,17 @@ class User(db.Model): logging.debug(traceback.format_exc()) # first register user will be in Administrator role - self.role_id = Role.query.filter_by(name='User').first().id if User.query.count() == 0: self.role_id = Role.query.filter_by(name='Administrator').first().id - - # user will be in Administrator role if part of LDAP Admin group - if LDAP_GROUP_SECURITY_ENABLED: - if isadmin == True: - self.role_id = Role.query.filter_by(name='Administrator').first().id + else: + self.role_id = Role.query.filter_by(name=role_name).first().id self.create_user() logging.info('Created user "{0}" in the DB'.format(self.username)) - # user already exists in database, set their admin status based on group membership (if enabled) + # user already exists in database, set their role based on group membership (if enabled) if LDAP_GROUP_SECURITY_ENABLED: - self.set_admin(isadmin) + self.set_role(role_name) return True else: @@ -430,9 +433,9 @@ class User(db.Model): User.query.filter(User.username == self.username).delete() db.session.commit() return True - except: + except Exception as e: db.session.rollback() - logging.error('Cannot delete user {0} from DB'.format(self.username)) + logging.error('Cannot delete user {0} from DB. DETAIL: {1}'.format(self.username, e)) return False def revoke_privilege(self): @@ -447,34 +450,21 @@ class User(db.Model): DomainUser.query.filter(DomainUser.user_id == user_id).delete() db.session.commit() return True - except: + except Exception as e: db.session.rollback() - logging.error('Cannot revoke user {0} privielges'.format(self.username)) + logging.error('Cannot revoke user {0} privielges. DETAIL: {1}'.format(self.username, e)) return False return False - def set_admin(self, is_admin): - """ - Set role for a user: - is_admin == True => Administrator - is_admin == False => User - """ - user_role_name = 'Administrator' if is_admin else 'User' - role = Role.query.filter(Role.name==user_role_name).first() - - try: - if role: - user = User.query.filter(User.username==self.username).first() - user.role_id = role.id - db.session.commit() - return True - else: - return False - except: - db.session.roleback() - logging.error('Cannot change user role in DB') - logging.debug(traceback.format_exc()) - return False + def set_role(self, role_name): + role = Role.query.filter(Role.name==role_name).first() + if role: + user = User.query.filter(User.username==self.username).first() + user.role_id = role.id + db.session.commit() + return {'status': True, 'msg': 'Set user role successfully'} + else: + return {'status': False, 'msg': 'Role does not exist'} class Account(db.Model): @@ -580,9 +570,9 @@ class Account(db.Model): db.session.commit() return True - except: + except Exception as e: db.session.rollback() - logging.error('Cannot delete account {0} from DB'.format(self.username)) + logging.error('Cannot delete account {0} from DB. DETAIL: {1}'.format(self.username, e)) return False def get_user(self): @@ -611,18 +601,18 @@ class Account(db.Model): for uid in removed_ids: AccountUser.query.filter(AccountUser.user_id == uid).filter(AccountUser.account_id==account_id).delete() db.session.commit() - except: + except Exception as e: db.session.rollback() - logging.error('Cannot revoke user privielges on account {0}'.format(self.name)) + logging.error('Cannot revoke user privielges on account {0}. DETAIL: {1}'.format(self.name, e)) try: for uid in added_ids: au = AccountUser(account_id, uid) db.session.add(au) db.session.commit() - except: + except Exception as e: db.session.rollback() - logging.error('Cannot grant user privileges to account {0}'.format(self.name)) + logging.error('Cannot grant user privileges to account {0}. DETAIL: {1}'.format(self.name, e)) def revoke_privileges_by_id(self, user_id): """ @@ -643,9 +633,9 @@ class Account(db.Model): db.session.add(au) db.session.commit() return True - except: + except Exception as e: db.session.rollback() - logging.error('Cannot add user privielges on account {0}'.format(self.name)) + logging.error('Cannot add user privielges on account {0}. DETAIL: {1}'.format(self.name, e)) return False def remove_user(self, user): @@ -656,9 +646,9 @@ class Account(db.Model): AccountUser.query.filter(AccountUser.user_id == user.id).filter(AccountUser.account_id == self.id).delete() db.session.commit() return True - except: + except Exception as e: db.session.rollback() - logging.error('Cannot revoke user privielges on account {0}'.format(self.name)) + logging.error('Cannot revoke user privielges on account {0}. DETAIL: {1}'.format(self.name, e)) return False @@ -707,8 +697,8 @@ class DomainSetting(db.Model): self.value = value db.session.commit() return True - except: - logging.error('Unable to set DomainSetting value') + except Exception as e: + logging.error('Unable to set DomainSetting value. DETAIL: {0}'.format(e)) logging.debug(traceback.format_exc()) db.session.rollback() return False @@ -784,7 +774,8 @@ class Domain(db.Model): try: domain = Domain.query.filter(Domain.name==name).first() return domain.id - except: + except Exception as e: + logging.error('Domain does not exist. ERROR: {0}'.format(e)) return None def update(self): @@ -818,8 +809,8 @@ class Domain(db.Model): # then remove domain Domain.query.filter(Domain.name == d).delete() db.session.commit() - except: - logging.error('Can not delete domain from DB') + except Exception as e: + logging.error('Can not delete domain from DB. DETAIL: {0}'.format(e)) logging.debug(traceback.format_exc()) db.session.rollback() @@ -911,7 +902,7 @@ class Domain(db.Model): return {'status': 'ok', 'msg': 'Added domain successfully'} except Exception as e: logging.error('Cannot add domain {0}'.format(domain_name)) - logging.debug(traceback.print_exc()) + logging.debug(traceback.format_exc()) return {'status': 'error', 'msg': 'Cannot add this domain.'} def update_soa_setting(self, domain_name, soa_edit_api): @@ -980,7 +971,7 @@ class Domain(db.Model): domain_users.append(tmp.username) if 0 != len(domain_users): self.name = domain_reverse_name - self.grant_privielges(domain_users) + self.grant_privileges(domain_users) return {'status': 'ok', 'msg': 'New reverse lookup domain created with granted privilages'} return {'status': 'ok', 'msg': 'New reverse lookup domain created without users'} return {'status': 'ok', 'msg': 'Reverse lookup domain already exists'} @@ -1009,12 +1000,12 @@ class Domain(db.Model): headers = {} headers['X-API-Key'] = self.PDNS_API_KEY try: - jdata = utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain_name)), headers=headers, method='DELETE') + utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain_name)), headers=headers, method='DELETE') logging.info('Delete domain {0} successfully'.format(domain_name)) return {'status': 'ok', 'msg': 'Delete domain successfully'} except Exception as e: logging.error('Cannot delete domain {0}'.format(domain_name)) - logging.debug(traceback.print_exc()) + logging.debug(traceback.format_exc()) return {'status': 'error', 'msg': 'Cannot delete domain'} def get_user(self): @@ -1027,7 +1018,7 @@ class Domain(db.Model): user_ids.append(q[0].user_id) return user_ids - def grant_privielges(self, new_user_list): + def grant_privileges(self, new_user_list): """ Reconfigure domain_user table """ @@ -1044,18 +1035,18 @@ class Domain(db.Model): for uid in removed_ids: DomainUser.query.filter(DomainUser.user_id == uid).filter(DomainUser.domain_id==domain_id).delete() db.session.commit() - except: + except Exception as e: db.session.rollback() - logging.error('Cannot revoke user privielges on domain {0}'.format(self.name)) + logging.error('Cannot revoke user privielges on domain {0}. DETAIL: {1}'.format(self.name, e)) try: for uid in added_ids: du = DomainUser(domain_id, uid) db.session.add(du) db.session.commit() - except: + except Exception as e: db.session.rollback() - logging.error('Cannot grant user privielges to domain {0}'.format(self.name)) + logging.error('Cannot grant user privielges to domain {0}. DETAIL: {1}'.format(self.name, e)) def update_from_master(self, domain_name): """ @@ -1066,9 +1057,10 @@ class Domain(db.Model): headers = {} headers['X-API-Key'] = self.PDNS_API_KEY try: - jdata = utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}/axfr-retrieve'.format(domain.name)), headers=headers, method='PUT') + utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}/axfr-retrieve'.format(domain.name)), headers=headers, method='PUT') return {'status': 'ok', 'msg': 'Update from Master successfully'} - except: + except Exception as e: + logging.error('Cannot update from master. DETAIL: {0}'.format(e)) return {'status': 'error', 'msg': 'There was something wrong, please contact administrator'} else: return {'status': 'error', 'msg': 'This domain doesnot exist'} @@ -1087,7 +1079,8 @@ class Domain(db.Model): return {'status': 'error', 'msg': 'DNSSEC is not enabled for this domain'} else: return {'status': 'ok', 'dnssec': jdata} - except: + except Exception as e: + logging.error('Cannot get domain dnssec. DETAIL: {0}'.format(e)) return {'status': 'error', 'msg': 'There was something wrong, please contact administrator'} else: return {'status': 'error', 'msg': 'This domain doesnot exist'} @@ -1120,8 +1113,9 @@ class Domain(db.Model): return {'status': 'ok'} - except: - logging.error(traceback.print_exc()) + except Exception as e: + logging.error('Cannot enable dns sec. DETAIL: {}'.format(e)) + logging.debug(traceback.format_exc()) return {'status': 'error', 'msg': 'There was something wrong, please contact administrator'} else: @@ -1151,8 +1145,9 @@ class Domain(db.Model): return {'status': 'ok'} - except: - logging.error(traceback.print_exc()) + except Exception as e: + logging.error('Cannot delete dnssec key. DETAIL: {0}'.format(e)) + logging.debug(traceback.format_exc()) return {'status': 'error', 'msg': 'There was something wrong, please contact administrator','domain': domain.name, 'id': key_id} else: @@ -1190,10 +1185,9 @@ class Domain(db.Model): if 'error' in jdata.keys(): logging.error(jdata['error']) return {'status': 'error', 'msg': jdata['error']} - else: self.update() - logging.info('account changed for domain {0} successfully'.format(domain_name)) + logging.info('Account changed for domain {0} successfully'.format(domain_name)) return {'status': 'ok', 'msg': 'account changed successfully'} except Exception as e: @@ -1202,8 +1196,6 @@ class Domain(db.Model): logging.error('Cannot change account for domain {0}'.format(domain_name)) return {'status': 'error', 'msg': 'Cannot change account for this domain.'} - return {'status': True, 'msg': 'Domain association successful'} - def get_account(self): """ Get current account associated with this domain @@ -1273,8 +1265,8 @@ class Record(object): headers['X-API-Key'] = self.PDNS_API_KEY try: jdata = utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers) - except: - logging.error("Cannot fetch domain's record data from remote powerdns api") + except Exception as e: + logging.error("Cannot fetch domain's record data from remote powerdns api. DETAIL: {0}".format(e)) return False if self.NEW_SCHEMA: @@ -1573,7 +1565,6 @@ class Record(object): self.add(domain_reverse_name) for r in deleted_records: if r['type'] in ['A', 'AAAA']: - r_name = r['name'] + '.' r_content = r['content'] reverse_host_address = dns.reversename.from_address(r_content).to_text() domain_reverse_name = d.get_reverse_domain_name(reverse_host_address) @@ -1606,8 +1597,8 @@ class Record(object): jdata = utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers, method='PATCH', data=data) logging.debug(jdata) return {'status': 'ok', 'msg': 'Record was removed successfully'} - except: - logging.error("Cannot remove record {0}/{1}/{2} from domain {3}".format(self.name, self.type, self.data, domain)) + except Exception as e: + logging.error("Cannot remove record {0}/{1}/{2} from domain {3}. DETAIL: {4}".format(self.name, self.type, self.data, domain, e)) return {'status': 'error', 'msg': 'There was something wrong, please contact administrator'} def is_allowed_edit(self): @@ -1683,7 +1674,7 @@ class Record(object): ] } try: - jdata = utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers, method='PATCH', data=data) + utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/localhost/zones/{0}'.format(domain)), headers=headers, method='PATCH', data=data) logging.debug("dyndns data: {0}".format(data)) return {'status': 'ok', 'msg': 'Record was updated successfully'} except Exception as e: @@ -1730,8 +1721,8 @@ class Server(object): try: jdata = utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/{0}/config'.format(self.server_id)), headers=headers, method='GET') return jdata - except: - logging.error("Can not get server configuration.") + except Exception as e: + logging.error("Can not get server configuration. DETAIL: {0}".format(e)) logging.debug(traceback.format_exc()) return [] @@ -1745,8 +1736,8 @@ class Server(object): try: jdata = utils.fetch_json(urljoin(self.PDNS_STATS_URL, self.API_EXTENDED_URL + '/servers/{0}/statistics'.format(self.server_id)), headers=headers, method='GET') return jdata - except: - logging.error("Can not get server statistics.") + except Exception as e: + logging.error("Can not get server statistics. DETAIL: {0}".format(e)) logging.debug(traceback.format_exc()) return [] @@ -1784,13 +1775,13 @@ class History(db.Model): Remove all history from DB """ try: - num_rows_deleted = db.session.query(History).delete() + db.session.query(History).delete() db.session.commit() logging.info("Removed all history") return True - except: + except Exception as e: db.session.rollback() - logging.error("Cannot remove history") + logging.error("Cannot remove history. DETAIL: {0}".format(e)) logging.debug(traceback.format_exc()) return False @@ -1798,7 +1789,6 @@ class Setting(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(64)) value = db.Column(db.Text()) - view = db.Column(db.String(64)) defaults = { 'maintenance': False, @@ -1808,9 +1798,10 @@ class Setting(db.Model): 'default_record_table_size': 15, 'default_domain_table_size': 10, 'auto_ptr': False, - 'allow_quick_edit': True, + 'record_quick_edit': True, 'pretty_ipv6_ptr': False, 'dnssec_admins_only': False, + 'allow_user_create_domain': False, 'bg_domain_updates': False, 'site_name': 'PowerDNS-Admin', 'pdns_api_url': '', @@ -1827,8 +1818,9 @@ class Setting(db.Model): 'ldap_filter_basic': '', 'ldap_filter_username': '', 'ldap_sg_enabled': False, - 'ldap_admin_group': False, - 'ldap_user_group': False, + 'ldap_admin_group': '', + 'ldap_operator_group': '', + 'ldap_user_group': '', 'github_oauth_enabled': False, 'github_oauth_key': '', 'github_oauth_secret': '', @@ -1873,8 +1865,8 @@ class Setting(db.Model): maintenance.value = mode db.session.commit() return True - except: - logging.error('Cannot set maintenance to {0}'.format(mode)) + except Exception as e: + logging.error('Cannot set maintenance to {0}. DETAIL: {1}'.format(mode, e)) logging.debug(traceback.format_exec()) db.session.rollback() return False @@ -1894,8 +1886,8 @@ class Setting(db.Model): current_setting.value = "True" db.session.commit() return True - except: - logging.error('Cannot toggle setting {0}'.format(setting)) + except Exception as e: + logging.error('Cannot toggle setting {0}. DETAIL: {1}'.format(setting, e)) logging.debug(traceback.format_exec()) db.session.rollback() return False @@ -1913,8 +1905,8 @@ class Setting(db.Model): current_setting.value = value db.session.commit() return True - except: - logging.error('Cannot edit setting {0}'.format(setting)) + except Exception as e: + logging.error('Cannot edit setting {0}. DETAIL: {1}'.format(setting, e)) logging.debug(traceback.format_exec()) db.session.rollback() return False @@ -1933,20 +1925,22 @@ class Setting(db.Model): return list(set(self.get_forward_records_allow_to_edit() + self.get_reverse_records_allow_to_edit())) def get_forward_records_allow_to_edit(self): - records = literal_eval(self.get('forward_records_allow_edit')) - return [r for r in records if records[r]] + records = self.get('forward_records_allow_edit') + f_records = literal_eval(records) if isinstance(records, str) else records + r_name = [r for r in f_records if f_records[r]] + # Sort alphabetically if python version is smaller than 3.6 + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 6): + r_name.sort() + return r_name def get_reverse_records_allow_to_edit(self): - records = literal_eval(self.get('reverse_records_allow_edit')) - return [r for r in records if records[r]] - - def get_view(self, view): - r = {} - settings = Setting.query.filter(Setting.view == view).all() - for setting in settings: - d = setting.__dict__ - r[d['name']] = d['value'] - return r + records = self.get('reverse_records_allow_edit') + r_records = literal_eval(records) if isinstance(records, str) else records + r_name = [r for r in r_records if r_records[r]] + # Sort alphabetically if python version is smaller than 3.6 + if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and sys.version_info[1] < 6): + r_name.sort() + return r_name class DomainTemplate(db.Model): diff --git a/app/oauth.py b/app/oauth.py index 17f30a0..17fd045 100644 --- a/app/oauth.py +++ b/app/oauth.py @@ -1,8 +1,7 @@ from ast import literal_eval from flask import request, session, redirect, url_for -from flask_oauthlib.client import OAuth -from app import app, oauth +from app import app, oauth_client from app.models import Setting # TODO: @@ -13,7 +12,7 @@ def github_oauth(): if not Setting().get('github_oauth_enabled'): return None - github = oauth.remote_app( + github = oauth_client.remote_app( 'github', consumer_key = Setting().get('github_oauth_key'), consumer_secret = Setting().get('github_oauth_secret'), @@ -48,7 +47,7 @@ def google_oauth(): if not Setting().get('google_oauth_enabled'): return None - google = oauth.remote_app( + google = oauth_client.remote_app( 'google', consumer_key=Setting().get('google_oauth_client_id'), consumer_secret=Setting().get('google_oauth_client_secret'), diff --git a/app/static/custom/js/custom.js b/app/static/custom/js/custom.js index 6442bb2..d9e33f7 100644 --- a/app/static/custom/js/custom.js +++ b/app/static/custom/js/custom.js @@ -1,7 +1,6 @@ var dnssecKeyList = [] function applyChanges(data, url, showResult, refreshPage) { - var success = false; $.ajax({ type : "POST", url : url, @@ -22,16 +21,20 @@ function applyChanges(data, url, showResult, refreshPage) { }, error : function(jqXHR, status) { + // console.log(jqXHR); + // var modal = $("#modal_error"); + // modal.find('.modal-body p').text(jqXHR["responseText"]); + // modal.modal('show'); console.log(jqXHR); var modal = $("#modal_error"); - modal.find('.modal-body p').text(jqXHR["responseText"]); + var responseJson = jQuery.parseJSON(jqXHR.responseText); + modal.find('.modal-body p').text(responseJson['msg']); modal.modal('show'); } }); } function applyRecordChanges(data, domain) { - var success = false; $.ajax({ type : "POST", url : $SCRIPT_ROOT + '/domain/' + domain + '/apply', @@ -62,8 +65,6 @@ function applyRecordChanges(data, domain) { } function getTableData(table) { - var rData = [] - // reformat - pretty format var records = [] table.rows().every(function() { @@ -81,16 +82,14 @@ function getTableData(table) { function saveRow(oTable, nRow) { + var status = 'Disabled'; var jqInputs = $(oTable.row(nRow).node()).find("input"); var jqSelect = $(oTable.row(nRow).node()).find("select"); if (jqSelect[1].value == 'false') { status = 'Active'; - } else { - status = 'Disabled'; } - oTable.cell(nRow,0).data(jqInputs[0].value); oTable.cell(nRow,1).data(jqSelect[0].value); oTable.cell(nRow,2).data(status); @@ -109,12 +108,12 @@ function saveRow(oTable, nRow) { function restoreRow(oTable, nRow) { var aData = oTable.row(nRow).data(); - var jqTds = $('>td', nRow); oTable.row(nRow).data(aData); oTable.draw(); } function editRow(oTable, nRow) { + var isDisabled = 'true'; var aData = oTable.row(nRow).data(); var jqTds = oTable.cells(nRow,'').nodes(); var record_types = ""; @@ -134,9 +133,6 @@ function editRow(oTable, nRow) { if (aData[2] == 'Active'){ isDisabled = 'false'; } - else { - isDisabled = 'true'; - } SelectElement('record_type', aData[1]); SelectElement('record_status', isDisabled); @@ -167,13 +163,14 @@ function enable_dns_sec(url) { function getdnssec(url, domain){ $.getJSON(url, function(data) { + var dnssec_footer = ''; var modal = $("#modal_dnssec_info"); if (data['status'] == 'error'){ modal.find('.modal-body p').text(data['msg']); } else { - dnssec_msg = ''; + var dnssec_msg = ''; var dnssec = data['dnssec']; if (dnssec.length == 0 && parseFloat(PDNS_VERSION) >= 4.1) { diff --git a/app/templates/admin_history.html b/app/templates/admin_history.html index 936cc7a..82f555b 100644 --- a/app/templates/admin_history.html +++ b/app/templates/admin_history.html @@ -23,7 +23,7 @@

History Management

-
diff --git a/app/templates/admin_manageuser.html b/app/templates/admin_manageuser.html index 653738e..a3aa85a 100644 --- a/app/templates/admin_manageuser.html +++ b/app/templates/admin_manageuser.html @@ -36,7 +36,7 @@ First Name Last Name Email - Admin + Role Privileges Action @@ -49,18 +49,22 @@ {{ user.lastname }} {{ user.email }} - + - - - @@ -93,14 +97,6 @@ "pageLength": 10 }); - // avoid losing icheck box style when database refreshed - $('#tbl_users').on('draw.dt', function () { - $('.admin_toggle').iCheck({ - handle: 'checkbox', - checkboxClass: 'icheckbox_square-blue' - }); - }); - // handle revocation of privileges $(document.body).on('click', '.button_revoke', function() { var modal = $("#modal_revoke"); @@ -129,24 +125,18 @@ }); - // initialize pretty checkboxes - $('.admin_toggle').iCheck({ - checkboxClass : 'icheckbox_square-blue', - increaseArea : '20%' // optional - }); - - // handle checkbox toggling - $(document.body).on('ifToggled', '.admin_toggle', function() { - var is_admin = $(this).prop('checked'); + // handle user role changing + $('.user_role').on('change', function() { + var role_name = this.value; var username = $(this).prop('id'); postdata = { - 'action' : 'set_admin', + 'action' : 'update_user_role', 'data' : { 'username' : username, - 'is_admin' : is_admin + 'role_name' : role_name } }; - applyChanges(postdata, $SCRIPT_ROOT + '/admin/manageuser'); + applyChanges(postdata, $SCRIPT_ROOT + '/admin/manageuser', showResult=true); }); {% endblock %} diff --git a/app/templates/admin_setting_authentication.html b/app/templates/admin_setting_authentication.html index e929065..e522178 100644 --- a/app/templates/admin_setting_authentication.html +++ b/app/templates/admin_setting_authentication.html @@ -133,6 +133,11 @@ +
+ + + +
@@ -197,6 +202,9 @@
  • Admin group - Your LDAP admin group.
  • +
  • + Operator group - Your LDAP operator group. +
  • User group - Your LDAP user group.
  • diff --git a/app/templates/admin_setting_basic.html b/app/templates/admin_setting_basic.html index b289f75..2b6834d 100644 --- a/app/templates/admin_setting_basic.html +++ b/app/templates/admin_setting_basic.html @@ -34,23 +34,22 @@ {% for setting in settings %} - {{ setting.name }} - {% if setting.value == "True" or setting.value == "False" %} - {{ setting.value }} - {% else %} - - {% endif %} + {{ setting }} + {% if SETTING.get(setting) in [True, False] %} + {{ SETTING.get(setting)|display_setting_state }} - {% if setting.value == "True" or setting.value == "False" %} - - {% else %} - - {% endif %} + {% endif %} {% endfor %} @@ -69,7 +68,7 @@