2019-12-02 03:32:03 +00:00
|
|
|
import sys
|
2020-06-19 01:47:51 +00:00
|
|
|
import traceback
|
|
|
|
|
2019-12-02 03:32:03 +00:00
|
|
|
import pytimeparse
|
|
|
|
from ast import literal_eval
|
|
|
|
from distutils.util import strtobool
|
2020-01-29 15:18:15 +00:00
|
|
|
from flask import current_app
|
2019-12-02 03:32:03 +00:00
|
|
|
|
|
|
|
from .base import db
|
|
|
|
|
|
|
|
|
|
|
|
class Setting(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
2021-12-11 14:49:05 +00:00
|
|
|
name = db.Column(db.String(64), unique=True, index=True)
|
2019-12-02 03:32:03 +00:00
|
|
|
value = db.Column(db.Text())
|
|
|
|
|
|
|
|
defaults = {
|
|
|
|
'maintenance': False,
|
|
|
|
'fullscreen_layout': True,
|
|
|
|
'record_helper': True,
|
|
|
|
'login_ldap_first': True,
|
|
|
|
'default_record_table_size': 15,
|
|
|
|
'default_domain_table_size': 10,
|
|
|
|
'auto_ptr': False,
|
|
|
|
'record_quick_edit': True,
|
|
|
|
'pretty_ipv6_ptr': False,
|
|
|
|
'dnssec_admins_only': False,
|
|
|
|
'allow_user_create_domain': False,
|
2021-10-30 19:21:45 +00:00
|
|
|
'allow_user_remove_domain': False,
|
2021-03-27 18:33:11 +00:00
|
|
|
'allow_user_view_history': False,
|
2022-06-18 12:20:49 +00:00
|
|
|
'delete_sso_accounts': False,
|
2019-12-02 03:32:03 +00:00
|
|
|
'bg_domain_updates': False,
|
2021-11-05 15:26:38 +00:00
|
|
|
'enable_api_rr_history': True,
|
2023-02-13 10:08:03 +00:00
|
|
|
'preserve_history': False,
|
2019-12-02 03:32:03 +00:00
|
|
|
'site_name': 'PowerDNS-Admin',
|
2019-12-21 14:43:03 +00:00
|
|
|
'site_url': 'http://localhost:9191',
|
2019-12-02 03:32:03 +00:00
|
|
|
'session_timeout': 10,
|
2019-12-18 08:25:20 +00:00
|
|
|
'warn_session_timeout': True,
|
2019-12-02 03:32:03 +00:00
|
|
|
'pdns_api_url': '',
|
|
|
|
'pdns_api_key': '',
|
|
|
|
'pdns_api_timeout': 30,
|
|
|
|
'pdns_version': '4.1.1',
|
2020-01-25 18:44:11 +00:00
|
|
|
'verify_ssl_connections': True,
|
2019-12-02 03:32:03 +00:00
|
|
|
'local_db_enabled': True,
|
|
|
|
'signup_enabled': True,
|
2021-08-05 17:37:48 +00:00
|
|
|
'autoprovisioning': False,
|
|
|
|
'urn_value':'',
|
|
|
|
'autoprovisioning_attribute': '',
|
|
|
|
'purge': False,
|
2019-12-21 14:43:03 +00:00
|
|
|
'verify_user_email': False,
|
2019-12-02 03:32:03 +00:00
|
|
|
'ldap_enabled': False,
|
|
|
|
'ldap_type': 'ldap',
|
|
|
|
'ldap_uri': '',
|
|
|
|
'ldap_base_dn': '',
|
|
|
|
'ldap_admin_username': '',
|
|
|
|
'ldap_admin_password': '',
|
|
|
|
'ldap_filter_basic': '',
|
2020-01-08 22:19:51 +00:00
|
|
|
'ldap_filter_group': '',
|
2019-12-02 03:32:03 +00:00
|
|
|
'ldap_filter_username': '',
|
2020-01-08 22:19:51 +00:00
|
|
|
'ldap_filter_groupname': '',
|
2019-12-02 03:32:03 +00:00
|
|
|
'ldap_sg_enabled': False,
|
|
|
|
'ldap_admin_group': '',
|
|
|
|
'ldap_operator_group': '',
|
|
|
|
'ldap_user_group': '',
|
|
|
|
'ldap_domain': '',
|
|
|
|
'github_oauth_enabled': False,
|
|
|
|
'github_oauth_key': '',
|
|
|
|
'github_oauth_secret': '',
|
|
|
|
'github_oauth_scope': 'email',
|
|
|
|
'github_oauth_api_url': 'https://api.github.com/user',
|
|
|
|
'github_oauth_token_url':
|
|
|
|
'https://github.com/login/oauth/access_token',
|
|
|
|
'github_oauth_authorize_url':
|
|
|
|
'https://github.com/login/oauth/authorize',
|
|
|
|
'google_oauth_enabled': False,
|
|
|
|
'google_oauth_client_id': '',
|
|
|
|
'google_oauth_client_secret': '',
|
|
|
|
'google_token_url': 'https://oauth2.googleapis.com/token',
|
|
|
|
'google_oauth_scope': 'openid email profile',
|
|
|
|
'google_authorize_url': 'https://accounts.google.com/o/oauth2/v2/auth',
|
|
|
|
'google_base_url': 'https://www.googleapis.com/oauth2/v3/',
|
2019-12-06 07:27:35 +00:00
|
|
|
'azure_oauth_enabled': False,
|
|
|
|
'azure_oauth_key': '',
|
|
|
|
'azure_oauth_secret': '',
|
|
|
|
'azure_oauth_scope': 'User.Read openid email profile',
|
|
|
|
'azure_oauth_api_url': 'https://graph.microsoft.com/v1.0/',
|
|
|
|
'azure_oauth_token_url':
|
|
|
|
'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/token',
|
|
|
|
'azure_oauth_authorize_url':
|
|
|
|
'https://login.microsoftonline.com/[tenancy]/oauth2/v2.0/authorize',
|
2020-01-03 02:36:38 +00:00
|
|
|
'azure_sg_enabled': False,
|
|
|
|
'azure_admin_group': '',
|
|
|
|
'azure_operator_group': '',
|
|
|
|
'azure_user_group': '',
|
2020-07-03 06:55:31 +00:00
|
|
|
'azure_group_accounts_enabled': False,
|
|
|
|
'azure_group_accounts_name': 'displayName',
|
|
|
|
'azure_group_accounts_name_re': '',
|
|
|
|
'azure_group_accounts_description': 'description',
|
|
|
|
'azure_group_accounts_description_re': '',
|
2019-12-02 03:32:03 +00:00
|
|
|
'oidc_oauth_enabled': False,
|
|
|
|
'oidc_oauth_key': '',
|
|
|
|
'oidc_oauth_secret': '',
|
|
|
|
'oidc_oauth_scope': 'email',
|
|
|
|
'oidc_oauth_api_url': '',
|
|
|
|
'oidc_oauth_token_url': '',
|
|
|
|
'oidc_oauth_authorize_url': '',
|
2023-02-23 08:21:01 +00:00
|
|
|
'oidc_oauth_metadata_url': '',
|
2020-08-05 11:46:07 +00:00
|
|
|
'oidc_oauth_logout_url': '',
|
2020-05-04 07:12:48 +00:00
|
|
|
'oidc_oauth_username': 'preferred_username',
|
|
|
|
'oidc_oauth_firstname': 'given_name',
|
2020-10-10 19:03:34 +00:00
|
|
|
'oidc_oauth_last_name': 'family_name',
|
2020-05-04 07:12:48 +00:00
|
|
|
'oidc_oauth_email': 'email',
|
2020-03-06 15:01:18 +00:00
|
|
|
'oidc_oauth_account_name_property': '',
|
|
|
|
'oidc_oauth_account_description_property': '',
|
2022-06-18 12:20:49 +00:00
|
|
|
'enforce_api_ttl': False,
|
2019-12-02 03:32:03 +00:00
|
|
|
'forward_records_allow_edit': {
|
|
|
|
'A': True,
|
|
|
|
'AAAA': True,
|
|
|
|
'AFSDB': False,
|
|
|
|
'ALIAS': False,
|
|
|
|
'CAA': True,
|
|
|
|
'CERT': False,
|
|
|
|
'CDNSKEY': False,
|
|
|
|
'CDS': False,
|
|
|
|
'CNAME': True,
|
|
|
|
'DNSKEY': False,
|
|
|
|
'DNAME': False,
|
|
|
|
'DS': False,
|
|
|
|
'HINFO': False,
|
|
|
|
'KEY': False,
|
|
|
|
'LOC': True,
|
|
|
|
'LUA': False,
|
|
|
|
'MX': True,
|
|
|
|
'NAPTR': False,
|
|
|
|
'NS': True,
|
|
|
|
'NSEC': False,
|
|
|
|
'NSEC3': False,
|
|
|
|
'NSEC3PARAM': False,
|
|
|
|
'OPENPGPKEY': False,
|
|
|
|
'PTR': True,
|
|
|
|
'RP': False,
|
|
|
|
'RRSIG': False,
|
|
|
|
'SOA': False,
|
|
|
|
'SPF': True,
|
|
|
|
'SSHFP': False,
|
|
|
|
'SRV': True,
|
|
|
|
'TKEY': False,
|
|
|
|
'TSIG': False,
|
|
|
|
'TLSA': False,
|
|
|
|
'SMIMEA': False,
|
|
|
|
'TXT': True,
|
|
|
|
'URI': False
|
|
|
|
},
|
|
|
|
'reverse_records_allow_edit': {
|
|
|
|
'A': False,
|
|
|
|
'AAAA': False,
|
|
|
|
'AFSDB': False,
|
|
|
|
'ALIAS': False,
|
|
|
|
'CAA': False,
|
|
|
|
'CERT': False,
|
|
|
|
'CDNSKEY': False,
|
|
|
|
'CDS': False,
|
|
|
|
'CNAME': False,
|
|
|
|
'DNSKEY': False,
|
|
|
|
'DNAME': False,
|
|
|
|
'DS': False,
|
|
|
|
'HINFO': False,
|
|
|
|
'KEY': False,
|
|
|
|
'LOC': True,
|
|
|
|
'LUA': False,
|
|
|
|
'MX': False,
|
|
|
|
'NAPTR': False,
|
|
|
|
'NS': True,
|
|
|
|
'NSEC': False,
|
|
|
|
'NSEC3': False,
|
|
|
|
'NSEC3PARAM': False,
|
|
|
|
'OPENPGPKEY': False,
|
|
|
|
'PTR': True,
|
|
|
|
'RP': False,
|
|
|
|
'RRSIG': False,
|
|
|
|
'SOA': False,
|
|
|
|
'SPF': False,
|
|
|
|
'SSHFP': False,
|
|
|
|
'SRV': False,
|
|
|
|
'TKEY': False,
|
|
|
|
'TSIG': False,
|
|
|
|
'TLSA': False,
|
|
|
|
'SMIMEA': False,
|
|
|
|
'TXT': True,
|
|
|
|
'URI': False
|
|
|
|
},
|
|
|
|
'ttl_options': '1 minute,5 minutes,30 minutes,60 minutes,24 hours',
|
2021-10-30 19:09:04 +00:00
|
|
|
'otp_field_enabled': True,
|
2021-06-01 14:15:31 +00:00
|
|
|
'custom_css': '',
|
2021-12-17 10:41:51 +00:00
|
|
|
'otp_force': False,
|
2022-06-17 15:50:51 +00:00
|
|
|
'max_history_records': 1000,
|
2021-12-01 13:35:05 +00:00
|
|
|
'deny_domain_override': False,
|
2022-05-27 11:01:46 +00:00
|
|
|
'account_name_extra_chars': False,
|
|
|
|
'gravatar_enabled': False,
|
2019-12-02 03:32:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, id=None, name=None, value=None):
|
|
|
|
self.id = id
|
|
|
|
self.name = name
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
# allow database autoincrement to do its own ID assignments
|
|
|
|
def __init__(self, name=None, value=None):
|
|
|
|
self.id = None
|
|
|
|
self.name = name
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def set_maintenance(self, mode):
|
|
|
|
maintenance = Setting.query.filter(
|
|
|
|
Setting.name == 'maintenance').first()
|
|
|
|
|
|
|
|
if maintenance is None:
|
|
|
|
value = self.defaults['maintenance']
|
|
|
|
maintenance = Setting(name='maintenance', value=str(value))
|
|
|
|
db.session.add(maintenance)
|
|
|
|
|
|
|
|
mode = str(mode)
|
|
|
|
|
|
|
|
try:
|
|
|
|
if maintenance.value != mode:
|
|
|
|
maintenance.value = mode
|
|
|
|
db.session.commit()
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
2020-01-29 15:18:15 +00:00
|
|
|
current_app.logger.error('Cannot set maintenance to {0}. DETAIL: {1}'.format(
|
2019-12-02 03:32:03 +00:00
|
|
|
mode, e))
|
2020-01-29 15:18:15 +00:00
|
|
|
current_app.logger.debug(traceback.format_exec())
|
2019-12-02 03:32:03 +00:00
|
|
|
db.session.rollback()
|
|
|
|
return False
|
|
|
|
|
|
|
|
def toggle(self, setting):
|
|
|
|
current_setting = Setting.query.filter(Setting.name == setting).first()
|
|
|
|
|
|
|
|
if current_setting is None:
|
|
|
|
value = self.defaults[setting]
|
|
|
|
current_setting = Setting(name=setting, value=str(value))
|
|
|
|
db.session.add(current_setting)
|
|
|
|
|
|
|
|
try:
|
|
|
|
if current_setting.value == "True":
|
|
|
|
current_setting.value = "False"
|
|
|
|
else:
|
|
|
|
current_setting.value = "True"
|
|
|
|
db.session.commit()
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
2020-01-29 15:18:15 +00:00
|
|
|
current_app.logger.error('Cannot toggle setting {0}. DETAIL: {1}'.format(
|
2019-12-02 03:32:03 +00:00
|
|
|
setting, e))
|
2020-01-29 15:18:15 +00:00
|
|
|
current_app.logger.debug(traceback.format_exec())
|
2019-12-02 03:32:03 +00:00
|
|
|
db.session.rollback()
|
|
|
|
return False
|
|
|
|
|
|
|
|
def set(self, setting, value):
|
|
|
|
current_setting = Setting.query.filter(Setting.name == setting).first()
|
|
|
|
|
|
|
|
if current_setting is None:
|
|
|
|
current_setting = Setting(name=setting, value=None)
|
|
|
|
db.session.add(current_setting)
|
|
|
|
|
|
|
|
value = str(value)
|
|
|
|
|
|
|
|
try:
|
|
|
|
current_setting.value = value
|
|
|
|
db.session.commit()
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
2020-01-29 15:18:15 +00:00
|
|
|
current_app.logger.error('Cannot edit setting {0}. DETAIL: {1}'.format(
|
2019-12-02 03:32:03 +00:00
|
|
|
setting, e))
|
2020-01-29 15:18:15 +00:00
|
|
|
current_app.logger.debug(traceback.format_exec())
|
2019-12-02 03:32:03 +00:00
|
|
|
db.session.rollback()
|
|
|
|
return False
|
|
|
|
|
|
|
|
def get(self, setting):
|
|
|
|
if setting in self.defaults:
|
2021-12-01 13:35:05 +00:00
|
|
|
|
2021-11-05 16:22:38 +00:00
|
|
|
if setting.upper() in current_app.config:
|
|
|
|
result = current_app.config[setting.upper()]
|
|
|
|
else:
|
|
|
|
result = self.query.filter(Setting.name == setting).first()
|
2021-12-01 13:35:05 +00:00
|
|
|
|
2019-12-02 03:32:03 +00:00
|
|
|
if result is not None:
|
2021-11-05 16:22:38 +00:00
|
|
|
if hasattr(result,'value'):
|
2021-12-01 13:35:05 +00:00
|
|
|
result = result.value
|
2021-11-05 16:22:38 +00:00
|
|
|
return strtobool(result) if result in [
|
2019-12-02 03:32:03 +00:00
|
|
|
'True', 'False'
|
2021-11-05 16:22:38 +00:00
|
|
|
] else result
|
2019-12-02 03:32:03 +00:00
|
|
|
else:
|
|
|
|
return self.defaults[setting]
|
|
|
|
else:
|
2020-01-29 15:18:15 +00:00
|
|
|
current_app.logger.error('Unknown setting queried: {0}'.format(setting))
|
2021-12-01 13:35:05 +00:00
|
|
|
|
2019-12-02 03:32:03 +00:00
|
|
|
def get_records_allow_to_edit(self):
|
|
|
|
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 = 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 = 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
|
|
|
|
|
|
|
|
def get_ttl_options(self):
|
|
|
|
return [(pytimeparse.parse(ttl), ttl)
|
|
|
|
for ttl in self.get('ttl_options').split(',')]
|