2016-08-12 16:49:53 +00:00
import base64
2015-12-13 09:34:12 +00:00
import json
2016-08-12 16:49:53 +00:00
import os
2015-12-13 09:34:12 +00:00
import traceback
2016-11-21 14:52:07 +00:00
import re
2016-08-12 16:49:53 +00:00
from distutils . util import strtobool
from distutils . version import StrictVersion
2015-12-13 09:34:12 +00:00
from functools import wraps
2016-08-12 16:49:53 +00:00
from io import BytesIO
import jinja2
2016-09-17 13:41:22 +00:00
import qrcode as qrc
import qrcode . image . svg as qrc_svg
2018-01-22 15:22:19 +00:00
from flask import g , request , make_response , jsonify , render_template , session , redirect , url_for , send_from_directory , abort , flash
2016-07-01 19:41:41 +00:00
from flask_login import login_user , logout_user , current_user , login_required
2015-12-16 17:50:28 +00:00
from werkzeug import secure_filename
2016-08-12 16:49:53 +00:00
from werkzeug . security import gen_salt
2015-12-13 09:34:12 +00:00
2018-01-22 15:22:19 +00:00
from . models import User , Domain , Record , Server , History , Anonymous , Setting , DomainSetting , DomainTemplate , DomainTemplateRecord
2017-09-22 14:28:09 +00:00
from app import app , login_manager , github , google
2018-03-30 06:49:35 +00:00
from app . lib import utils
2018-03-31 01:21:02 +00:00
from app . lib . log import logger
2018-03-31 00:32:46 +00:00
from app . decorators import admin_role_required , can_access_domain
2016-06-16 08:33:05 +00:00
2018-03-31 01:21:02 +00:00
# LOG CONFIG
logging = logger ( ' MODEL ' , app . config [ ' LOG_LEVEL ' ] , app . config [ ' LOG_FILE ' ] ) . config ( )
2015-12-13 09:34:12 +00:00
2018-03-31 01:21:02 +00:00
# FILTERS
2015-12-13 09:34:12 +00:00
jinja2 . filters . FILTERS [ ' display_record_name ' ] = utils . display_record_name
jinja2 . filters . FILTERS [ ' display_master_name ' ] = utils . display_master_name
jinja2 . filters . FILTERS [ ' display_second_to_time ' ] = utils . display_time
2016-07-13 14:33:21 +00:00
jinja2 . filters . FILTERS [ ' email_to_gravatar_url ' ] = utils . email_to_gravatar_url
2015-12-13 09:34:12 +00:00
2016-06-26 13:53:29 +00:00
# Flag for pdns v4.x.x
# TODO: Find another way to do this
PDNS_VERSION = app . config [ ' PDNS_VERSION ' ]
if StrictVersion ( PDNS_VERSION ) > = StrictVersion ( ' 4.0.0 ' ) :
NEW_SCHEMA = True
else :
NEW_SCHEMA = False
2018-03-30 06:49:35 +00:00
2016-04-29 21:36:37 +00:00
@app.context_processor
def inject_fullscreen_layout_setting ( ) :
fullscreen_layout_setting = Setting . query . filter ( Setting . name == ' fullscreen_layout ' ) . first ( )
return dict ( fullscreen_layout_setting = strtobool ( fullscreen_layout_setting . value ) )
2018-03-30 06:49:35 +00:00
2016-05-15 18:47:02 +00:00
@app.context_processor
def inject_record_helper_setting ( ) :
record_helper_setting = Setting . query . filter ( Setting . name == ' record_helper ' ) . first ( )
return dict ( record_helper_setting = strtobool ( record_helper_setting . value ) )
2018-03-30 06:49:35 +00:00
2016-07-05 15:28:02 +00:00
@app.context_processor
def inject_login_ldap_first_setting ( ) :
login_ldap_first_setting = Setting . query . filter ( Setting . name == ' login_ldap_first ' ) . first ( )
return dict ( login_ldap_first_setting = strtobool ( login_ldap_first_setting . value ) )
2018-03-30 06:49:35 +00:00
2016-06-09 01:23:08 +00:00
@app.context_processor
def inject_default_record_table_size_setting ( ) :
default_record_table_size_setting = Setting . query . filter ( Setting . name == ' default_record_table_size ' ) . first ( )
return dict ( default_record_table_size_setting = default_record_table_size_setting . value )
2018-03-30 06:49:35 +00:00
2016-07-05 15:14:41 +00:00
@app.context_processor
def inject_default_domain_table_size_setting ( ) :
default_domain_table_size_setting = Setting . query . filter ( Setting . name == ' default_domain_table_size ' ) . first ( )
return dict ( default_domain_table_size_setting = default_domain_table_size_setting . value )
2018-03-30 06:49:35 +00:00
2016-11-21 12:42:00 +00:00
@app.context_processor
def inject_auto_ptr_setting ( ) :
auto_ptr_setting = Setting . query . filter ( Setting . name == ' auto_ptr ' ) . first ( )
2018-04-01 08:51:56 +00:00
if auto_ptr_setting is None :
return dict ( auto_ptr_setting = False )
else :
return dict ( auto_ptr_setting = strtobool ( auto_ptr_setting . value ) )
2016-11-21 12:42:00 +00:00
2018-03-30 06:49:35 +00:00
2015-12-13 09:34:12 +00:00
# START USER AUTHENTICATION HANDLER
@app.before_request
def before_request ( ) :
# check site maintenance mode first
maintenance = Setting . query . filter ( Setting . name == ' maintenance ' ) . first ( )
if maintenance and maintenance . value == ' True ' :
return render_template ( ' maintenance.html ' )
# check if user is anonymous
g . user = current_user
login_manager . anonymous_user = Anonymous
2016-07-13 14:33:21 +00:00
2015-12-13 09:34:12 +00:00
@login_manager.user_loader
def load_user ( id ) :
"""
This will be current_user
"""
return User . query . get ( int ( id ) )
2016-06-20 09:32:14 +00:00
def dyndns_login_required ( f ) :
@wraps ( f )
def decorated_function ( * args , * * kwargs ) :
if current_user . is_authenticated is False :
return render_template ( ' dyndns.html ' , response = ' badauth ' ) , 200
return f ( * args , * * kwargs )
return decorated_function
2018-03-30 06:49:35 +00:00
2016-06-20 09:32:14 +00:00
@login_manager.request_loader
def login_via_authorization_header ( request ) :
auth_header = request . headers . get ( ' Authorization ' )
if auth_header :
auth_header = auth_header . replace ( ' Basic ' , ' ' , 1 )
try :
auth_header = base64 . b64decode ( auth_header )
username , password = auth_header . split ( " : " )
2018-03-30 06:49:35 +00:00
except TypeError as e :
2016-06-20 09:32:14 +00:00
return None
user = User ( username = username , password = password , plain_text_password = password )
try :
auth = user . is_validate ( method = ' LOCAL ' )
if auth == False :
return None
else :
login_user ( user , remember = False )
return user
2018-03-30 06:49:35 +00:00
except :
2016-06-20 09:32:14 +00:00
return None
return None
2015-12-13 09:34:12 +00:00
# END USER AUTHENTICATION HANDLER
# START VIEWS
2016-05-15 22:01:57 +00:00
@app.errorhandler ( 400 )
def http_bad_request ( e ) :
return redirect ( url_for ( ' error ' , code = 400 ) )
2018-03-30 06:49:35 +00:00
2016-05-15 22:01:57 +00:00
@app.errorhandler ( 401 )
def http_unauthorized ( e ) :
return redirect ( url_for ( ' error ' , code = 401 ) )
2018-03-30 06:49:35 +00:00
2016-05-15 22:01:57 +00:00
@app.errorhandler ( 404 )
def http_internal_server_error ( e ) :
return redirect ( url_for ( ' error ' , code = 404 ) )
2018-03-30 06:49:35 +00:00
2016-05-15 22:01:57 +00:00
@app.errorhandler ( 500 )
def http_page_not_found ( e ) :
return redirect ( url_for ( ' error ' , code = 500 ) )
2018-03-30 06:49:35 +00:00
2018-03-30 23:52:14 +00:00
@app.route ( ' /error/<path:code> ' )
2015-12-13 09:34:12 +00:00
def error ( code , msg = None ) :
supported_code = ( ' 400 ' , ' 401 ' , ' 404 ' , ' 500 ' )
if code in supported_code :
2018-04-01 00:57:41 +00:00
return render_template ( ' errors/ {0} .html ' . format ( code ) , msg = msg ) , int ( code )
2015-12-13 09:34:12 +00:00
else :
2016-05-15 22:01:57 +00:00
return render_template ( ' errors/404.html ' ) , 404
2015-12-13 09:34:12 +00:00
2018-03-30 06:49:35 +00:00
2016-04-23 00:19:03 +00:00
@app.route ( ' /register ' , methods = [ ' GET ' ] )
def register ( ) :
2016-06-13 04:48:48 +00:00
SIGNUP_ENABLED = app . config [ ' SIGNUP_ENABLED ' ]
if SIGNUP_ENABLED :
return render_template ( ' register.html ' )
else :
return render_template ( ' errors/404.html ' ) , 404
2015-12-13 09:34:12 +00:00
2018-03-30 06:49:35 +00:00
2017-09-22 14:28:09 +00:00
@app.route ( ' /google/login ' )
def google_login ( ) :
if not app . config . get ( ' GOOGLE_OAUTH_ENABLE ' ) :
return abort ( 400 )
return google . authorize ( callback = url_for ( ' authorized ' , _external = True ) )
2016-08-05 08:20:41 +00:00
@app.route ( ' /github/login ' )
def github_login ( ) :
if not app . config . get ( ' GITHUB_OAUTH_ENABLE ' ) :
return abort ( 400 )
return github . authorize ( callback = url_for ( ' authorized ' , _external = True ) )
2018-03-30 06:49:35 +00:00
2015-12-13 09:34:12 +00:00
@app.route ( ' /login ' , methods = [ ' GET ' , ' POST ' ] )
@login_manager.unauthorized_handler
def login ( ) :
2016-04-29 18:26:10 +00:00
LOGIN_TITLE = app . config [ ' LOGIN_TITLE ' ] if ' LOGIN_TITLE ' in app . config . keys ( ) else ' '
BASIC_ENABLED = app . config [ ' BASIC_ENABLED ' ]
SIGNUP_ENABLED = app . config [ ' SIGNUP_ENABLED ' ]
2018-04-01 08:08:55 +00:00
LDAP_ENABLE = app . config . get ( ' LDAP_ENABLE ' )
2016-08-05 08:20:41 +00:00
GITHUB_ENABLE = app . config . get ( ' GITHUB_OAUTH_ENABLE ' )
2017-09-22 14:28:09 +00:00
GOOGLE_ENABLE = app . config . get ( ' GOOGLE_OAUTH_ENABLE ' )
2015-12-13 09:34:12 +00:00
if g . user is not None and current_user . is_authenticated :
return redirect ( url_for ( ' dashboard ' ) )
2017-09-22 14:28:09 +00:00
if ' google_token ' in session :
user_data = google . get ( ' userinfo ' ) . data
first_name = user_data [ ' given_name ' ]
surname = user_data [ ' family_name ' ]
email = user_data [ ' email ' ]
user = User . query . filter_by ( username = email ) . first ( )
if not user :
# create user
user = User ( username = email ,
firstname = first_name ,
lastname = surname ,
plain_text_password = gen_salt ( 7 ) ,
email = email )
2018-03-30 10:43:34 +00:00
result = user . create_local_user ( )
if not result [ ' status ' ] :
session . pop ( ' google_token ' , None )
return redirect ( url_for ( ' login ' ) )
2017-09-22 14:28:09 +00:00
session [ ' user_id ' ] = user . id
login_user ( user , remember = False )
return redirect ( url_for ( ' index ' ) )
2016-08-05 08:20:41 +00:00
if ' github_token ' in session :
me = github . get ( ' user ' )
user_info = me . data
user = User . query . filter_by ( username = user_info [ ' name ' ] ) . first ( )
if not user :
# create user
user = User ( username = user_info [ ' name ' ] ,
2016-08-12 16:49:53 +00:00
plain_text_password = gen_salt ( 7 ) ,
2016-08-05 08:20:41 +00:00
email = user_info [ ' email ' ] )
2018-03-30 10:43:34 +00:00
result = user . create_local_user ( )
if not result [ ' status ' ] :
session . pop ( ' github_token ' , None )
return redirect ( url_for ( ' login ' ) )
2016-08-05 08:20:41 +00:00
session [ ' user_id ' ] = user . id
login_user ( user , remember = False )
return redirect ( url_for ( ' index ' ) )
2015-12-13 09:34:12 +00:00
if request . method == ' GET ' :
2016-08-05 08:20:41 +00:00
return render_template ( ' login.html ' ,
2016-08-12 16:49:53 +00:00
github_enabled = GITHUB_ENABLE ,
2017-09-22 14:28:09 +00:00
google_enabled = GOOGLE_ENABLE ,
2018-04-01 08:08:55 +00:00
ldap_enabled = LDAP_ENABLE , login_title = LOGIN_TITLE ,
2016-08-12 16:49:53 +00:00
basic_enabled = BASIC_ENABLED , signup_enabled = SIGNUP_ENABLED )
2016-08-05 08:20:41 +00:00
2015-12-13 09:34:12 +00:00
# process login
username = request . form [ ' username ' ]
password = request . form [ ' password ' ]
2016-08-12 16:49:53 +00:00
otp_token = request . form . get ( ' otptoken ' )
auth_method = request . form . get ( ' auth_method ' , ' LOCAL ' )
2015-12-13 09:34:12 +00:00
# addition fields for registration case
2016-08-12 16:49:53 +00:00
firstname = request . form . get ( ' firstname ' )
lastname = request . form . get ( ' lastname ' )
email = request . form . get ( ' email ' )
rpassword = request . form . get ( ' rpassword ' )
2016-08-05 08:20:41 +00:00
2015-12-13 09:34:12 +00:00
if None in [ firstname , lastname , email ] :
#login case
remember_me = False
if ' remember ' in request . form :
remember_me = True
user = User ( username = username , password = password , plain_text_password = password )
try :
auth = user . is_validate ( method = auth_method )
if auth == False :
2018-04-01 08:08:55 +00:00
return render_template ( ' login.html ' , error = ' Invalid credentials ' , ldap_enabled = LDAP_ENABLE , login_title = LOGIN_TITLE , basic_enabled = BASIC_ENABLED , signup_enabled = SIGNUP_ENABLED )
2018-03-30 06:49:35 +00:00
except Exception as e :
2018-04-01 08:08:55 +00:00
return render_template ( ' login.html ' , error = e , ldap_enabled = LDAP_ENABLE , login_title = LOGIN_TITLE , basic_enabled = BASIC_ENABLED , signup_enabled = SIGNUP_ENABLED )
2015-12-13 09:34:12 +00:00
2016-06-16 08:33:05 +00:00
# check if user enabled OPT authentication
if user . otp_secret :
2018-05-07 13:32:15 +00:00
if otp_token and isinstance ( otp_token , int ) :
2016-06-16 08:33:05 +00:00
good_token = user . verify_totp ( otp_token )
if not good_token :
2018-04-01 08:08:55 +00:00
return render_template ( ' login.html ' , error = ' Invalid credentials ' , ldap_enabled = LDAP_ENABLE , login_title = LOGIN_TITLE , basic_enabled = BASIC_ENABLED , signup_enabled = SIGNUP_ENABLED )
2016-06-16 08:33:05 +00:00
else :
2018-04-01 08:08:55 +00:00
return render_template ( ' login.html ' , error = ' Token required ' , ldap_enabled = LDAP_ENABLE , login_title = LOGIN_TITLE , basic_enabled = BASIC_ENABLED , signup_enabled = SIGNUP_ENABLED )
2016-06-16 08:33:05 +00:00
2015-12-13 09:34:12 +00:00
login_user ( user , remember = remember_me )
return redirect ( request . args . get ( ' next ' ) or url_for ( ' index ' ) )
else :
# registration case
user = User ( username = username , plain_text_password = password , firstname = firstname , lastname = lastname , email = email )
2016-08-05 08:20:41 +00:00
2016-04-23 00:19:03 +00:00
# TODO: Move this into the JavaScript
# validate password and password confirmation
if password != rpassword :
error = " Passsword and confirmation do not match "
return render_template ( ' register.html ' , error = error )
2016-08-05 08:20:41 +00:00
2015-12-13 09:34:12 +00:00
try :
result = user . create_local_user ( )
2018-03-30 10:43:34 +00:00
if result [ ' status ' ] == True :
2018-04-01 08:08:55 +00:00
return render_template ( ' login.html ' , username = username , password = password , ldap_enabled = LDAP_ENABLE , login_title = LOGIN_TITLE , basic_enabled = BASIC_ENABLED , signup_enabled = SIGNUP_ENABLED )
2015-12-13 09:34:12 +00:00
else :
2018-03-30 10:43:34 +00:00
return render_template ( ' register.html ' , error = result [ ' msg ' ] )
2018-03-30 06:49:35 +00:00
except Exception as e :
return render_template ( ' register.html ' , error = e )
2015-12-13 09:34:12 +00:00
@app.route ( ' /logout ' )
def logout ( ) :
2016-08-12 16:49:53 +00:00
session . pop ( ' user_id ' , None )
session . pop ( ' github_token ' , None )
2017-09-22 14:28:09 +00:00
session . pop ( ' google_token ' , None )
2015-12-13 09:34:12 +00:00
logout_user ( )
2016-08-05 08:20:41 +00:00
return redirect ( url_for ( ' login ' ) )
2015-12-13 09:34:12 +00:00
@app.route ( ' /dashboard ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def dashboard ( ) :
d = Domain ( ) . update ( )
2016-04-27 23:19:25 +00:00
# stats for dashboard
2016-04-29 16:29:08 +00:00
domain_count = Domain . query . count ( )
2016-04-27 23:19:25 +00:00
users = User . query . all ( )
history_number = History . query . count ( )
2016-06-30 20:04:59 +00:00
history = History . query . order_by ( History . created_on . desc ( ) ) . limit ( 4 )
2016-04-27 23:19:25 +00:00
server = Server ( server_id = ' localhost ' )
statistics = server . get_statistic ( )
if statistics :
2018-03-30 06:49:35 +00:00
uptime = list ( [ uptime for uptime in statistics if uptime [ ' name ' ] == ' uptime ' ] ) [ 0 ] [ ' value ' ]
2016-04-27 23:19:25 +00:00
else :
uptime = 0
2017-06-30 16:18:06 +00:00
return render_template ( ' dashboard.html ' , domain_count = domain_count , users = users , history_number = history_number , uptime = uptime , histories = history )
@app.route ( ' /dashboard-domains ' , methods = [ ' GET ' ] )
@login_required
def dashboard_domains ( ) :
if current_user . role . name == ' Administrator ' :
domains = Domain . query
else :
2017-09-15 13:14:04 +00:00
domains = User ( id = current_user . id ) . get_domain_query ( )
2017-06-30 16:18:06 +00:00
template = app . jinja_env . get_template ( " dashboard_domain.html " )
render = template . make_module ( vars = { " current_user " : current_user } )
columns = [ Domain . name , Domain . dnssec , Domain . type , Domain . serial , Domain . master ]
# History.created_on.desc()
order_by = [ ]
for i in range ( len ( columns ) ) :
2018-04-01 00:57:41 +00:00
column_index = request . args . get ( " order[ {0} ][column] " . format ( i ) )
sort_direction = request . args . get ( " order[ {0} ][dir] " . format ( i ) )
2017-06-30 16:18:06 +00:00
if column_index is None :
break
if sort_direction != " asc " and sort_direction != " desc " :
sort_direction = " asc "
column = columns [ int ( column_index ) ]
order_by . append ( getattr ( column , sort_direction ) ( ) )
if order_by :
domains = domains . order_by ( * order_by )
total_count = domains . count ( )
search = request . args . get ( " search[value] " )
if search :
start = " " if search . startswith ( " ^ " ) else " % "
end = " " if search . endswith ( " $ " ) else " % "
domains = domains . filter ( Domain . name . ilike ( start + search . strip ( " ^$ " ) + end ) )
filtered_count = domains . count ( )
start = int ( request . args . get ( " start " , 0 ) )
length = min ( int ( request . args . get ( " length " , 0 ) ) , 100 )
2018-03-30 08:40:43 +00:00
if length != - 1 :
domains = domains [ start : start + length ]
2017-06-30 16:18:06 +00:00
2017-09-15 13:14:04 +00:00
if current_user . role . name != ' Administrator ' :
domains = [ d [ 2 ] for d in domains ]
2017-06-30 16:18:06 +00:00
data = [ ]
for domain in domains :
data . append ( [
render . name ( domain ) ,
render . dnssec ( domain ) ,
render . type ( domain ) ,
render . serial ( domain ) ,
render . master ( domain ) ,
render . actions ( domain ) ,
] )
response_data = {
" draw " : int ( request . args . get ( " draw " , 0 ) ) ,
" recordsTotal " : total_count ,
" recordsFiltered " : filtered_count ,
" data " : data ,
}
return jsonify ( response_data )
2015-12-13 09:34:12 +00:00
2016-08-02 08:59:31 +00:00
@app.route ( ' /domain/<path:domain_name> ' , methods = [ ' GET ' , ' POST ' ] )
2015-12-13 09:34:12 +00:00
@app.route ( ' /domain ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
2018-03-31 00:32:46 +00:00
@can_access_domain
2015-12-13 09:34:12 +00:00
def domain ( domain_name ) :
r = Record ( )
domain = Domain . query . filter ( Domain . name == domain_name ) . first ( )
if domain :
# query domain info from PowerDNS API
zone_info = r . get_record_data ( domain . name )
if zone_info :
jrecords = zone_info [ ' records ' ]
else :
# can not get any record, API server might be down
return redirect ( url_for ( ' error ' , code = 500 ) )
records = [ ]
2016-06-26 13:53:29 +00:00
#TODO: This should be done in the "model" instead of "view"
if NEW_SCHEMA :
for jr in jrecords :
if jr [ ' type ' ] in app . config [ ' RECORDS_ALLOW_EDIT ' ] :
for subrecord in jr [ ' records ' ] :
record = Record ( name = jr [ ' name ' ] , type = jr [ ' type ' ] , status = ' Disabled ' if subrecord [ ' disabled ' ] else ' Active ' , ttl = jr [ ' ttl ' ] , data = subrecord [ ' content ' ] )
records . append ( record )
else :
for jr in jrecords :
if jr [ ' type ' ] in app . config [ ' RECORDS_ALLOW_EDIT ' ] :
record = Record ( name = jr [ ' name ' ] , type = jr [ ' type ' ] , status = ' Disabled ' if jr [ ' disabled ' ] else ' Active ' , ttl = jr [ ' ttl ' ] , data = jr [ ' content ' ] )
2016-06-08 04:00:55 +00:00
records . append ( record )
2016-11-21 14:52:07 +00:00
if not re . search ( ' ip6 \ .arpa|in-addr \ .arpa$ ' , domain_name ) :
editable_records = app . config [ ' RECORDS_ALLOW_EDIT ' ]
else :
2017-07-03 03:53:26 +00:00
editable_records = app . config [ ' REVERSE_ALLOW_EDIT ' ]
2016-11-21 14:52:07 +00:00
return render_template ( ' domain.html ' , domain = domain , records = records , editable_records = editable_records )
2015-12-13 09:34:12 +00:00
else :
return redirect ( url_for ( ' error ' , code = 404 ) )
@app.route ( ' /admin/domain/add ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_role_required
def domain_add ( ) :
2018-01-22 15:22:19 +00:00
templates = DomainTemplate . query . all ( )
2015-12-13 09:34:12 +00:00
if request . method == ' POST ' :
try :
domain_name = request . form . getlist ( ' domain_name ' ) [ 0 ]
domain_type = request . form . getlist ( ' radio_type ' ) [ 0 ]
2018-01-22 15:22:19 +00:00
domain_template = request . form . getlist ( ' domain_template ' ) [ 0 ]
2018-03-31 01:21:02 +00:00
logging . info ( " Selected template ==== {0} " . format ( domain_template ) )
2016-03-05 10:04:12 +00:00
soa_edit_api = request . form . getlist ( ' radio_type_soa_edit_api ' ) [ 0 ]
2016-01-15 04:58:53 +00:00
if ' ' in domain_name or not domain_name or not domain_type :
2016-05-15 22:01:57 +00:00
return render_template ( ' errors/400.html ' , msg = " Please correct your input " ) , 400
2016-01-15 04:58:53 +00:00
2015-12-13 09:34:12 +00:00
if domain_type == ' slave ' :
if request . form . getlist ( ' domain_master_address ' ) :
domain_master_string = request . form . getlist ( ' domain_master_address ' ) [ 0 ]
domain_master_string = domain_master_string . replace ( ' ' , ' ' )
domain_master_ips = domain_master_string . split ( ' , ' )
else :
domain_master_ips = [ ]
d = Domain ( )
2016-03-05 10:04:12 +00:00
result = d . add ( domain_name = domain_name , domain_type = domain_type , soa_edit_api = soa_edit_api , domain_master_ips = domain_master_ips )
2015-12-13 09:34:12 +00:00
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Add domain {0} ' . format ( domain_name ) , detail = str ( { ' domain_type ' : domain_type , ' domain_master_ips ' : domain_master_ips } ) , created_by = current_user . username )
2015-12-13 09:34:12 +00:00
history . add ( )
2018-01-22 15:22:19 +00:00
if domain_template != ' 0 ' :
template = DomainTemplate . query . filter ( DomainTemplate . id == domain_template ) . first ( )
template_records = DomainTemplateRecord . query . filter ( DomainTemplateRecord . template_id == domain_template ) . all ( )
record_data = [ ]
for template_record in template_records :
record_row = { ' record_data ' : template_record . data , ' record_name ' : template_record . name , ' record_status ' : template_record . status , ' record_ttl ' : template_record . ttl , ' record_type ' : template_record . type }
record_data . append ( record_row )
r = Record ( )
result = r . apply ( domain_name , record_data )
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Applying template {0} to {1} , created records successfully. ' . format ( template . name , domain_name ) , detail = str ( result ) , created_by = current_user . username )
2018-01-22 15:22:19 +00:00
history . add ( )
else :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Applying template {0} to {1} , FAILED to created records. ' . format ( template . name , domain_name ) , detail = str ( result ) , created_by = current_user . username )
2018-01-22 15:22:19 +00:00
history . add ( )
2015-12-13 09:34:12 +00:00
return redirect ( url_for ( ' dashboard ' ) )
else :
2016-05-15 22:01:57 +00:00
return render_template ( ' errors/400.html ' , msg = result [ ' msg ' ] ) , 400
2015-12-13 09:34:12 +00:00
except :
2018-03-31 01:21:02 +00:00
logging . error ( traceback . print_exc ( ) )
2015-12-13 09:34:12 +00:00
return redirect ( url_for ( ' error ' , code = 500 ) )
2018-01-22 15:22:19 +00:00
return render_template ( ' domain_add.html ' , templates = templates )
2015-12-13 09:34:12 +00:00
2018-03-30 23:52:14 +00:00
@app.route ( ' /admin/domain/<path:domain_name>/delete ' , methods = [ ' GET ' ] )
2015-12-13 09:34:12 +00:00
@login_required
@admin_role_required
def domain_delete ( domain_name ) :
d = Domain ( )
result = d . delete ( domain_name )
2016-08-05 08:20:41 +00:00
2015-12-13 09:34:12 +00:00
if result [ ' status ' ] == ' error ' :
return redirect ( url_for ( ' error ' , code = 500 ) )
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Delete domain {0} ' . format ( domain_name ) , created_by = current_user . username )
2015-12-13 09:34:12 +00:00
history . add ( )
return redirect ( url_for ( ' dashboard ' ) )
2018-03-30 23:52:14 +00:00
@app.route ( ' /admin/domain/<path:domain_name>/manage ' , methods = [ ' GET ' , ' POST ' ] )
2015-12-13 09:34:12 +00:00
@login_required
@admin_role_required
def domain_management ( domain_name ) :
if request . method == ' GET ' :
domain = Domain . query . filter ( Domain . name == domain_name ) . first ( )
if not domain :
return redirect ( url_for ( ' error ' , code = 404 ) )
users = User . query . all ( )
# get list of user ids to initilize selection data
d = Domain ( name = domain_name )
domain_user_ids = d . get_user ( )
return render_template ( ' domain_management.html ' , domain = domain , users = users , domain_user_ids = domain_user_ids )
if request . method == ' POST ' :
# username in right column
new_user_list = request . form . getlist ( ' domain_multi_user[] ' )
# get list of user ids to compare
d = Domain ( name = domain_name )
domain_user_ids = d . get_user ( )
2016-08-05 08:20:41 +00:00
# grant/revoke user privielges
2015-12-13 09:34:12 +00:00
d . grant_privielges ( new_user_list )
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Change domain {0} access control ' . format ( domain_name ) , detail = str ( { ' user_has_access ' : new_user_list } ) , created_by = current_user . username )
2015-12-13 09:34:12 +00:00
history . add ( )
return redirect ( url_for ( ' domain_management ' , domain_name = domain_name ) )
2016-03-05 10:04:12 +00:00
2018-03-30 23:52:14 +00:00
@app.route ( ' /domain/<path:domain_name>/apply ' , methods = [ ' POST ' ] , strict_slashes = False )
2015-12-13 09:34:12 +00:00
@login_required
2018-03-31 00:32:46 +00:00
@can_access_domain
2015-12-13 09:34:12 +00:00
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 ' }
"""
#TODO: filter removed records / name modified records.
try :
2018-03-30 06:49:35 +00:00
jdata = request . json
2015-12-13 09:34:12 +00:00
r = Record ( )
2016-08-19 23:04:20 +00:00
result = r . apply ( domain_name , jdata )
2015-12-13 09:34:12 +00:00
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Apply record changes to domain {0} ' . format ( domain_name ) , detail = str ( jdata ) , created_by = current_user . username )
2015-12-13 09:34:12 +00:00
history . add ( )
return make_response ( jsonify ( result ) , 200 )
else :
return make_response ( jsonify ( result ) , 400 )
except :
2018-03-31 01:21:02 +00:00
logging . error ( traceback . print_exc ( ) )
2015-12-13 09:34:12 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Error when applying new changes ' } ) , 500 )
2018-03-30 23:52:14 +00:00
@app.route ( ' /domain/<path:domain_name>/update ' , methods = [ ' POST ' ] , strict_slashes = False )
2015-12-13 09:34:12 +00:00
@login_required
2018-03-31 00:32:46 +00:00
@can_access_domain
2015-12-13 09:34:12 +00:00
def record_update ( domain_name ) :
"""
This route is used for domain work as Slave Zone only
Pulling the records update from its Master
"""
try :
2018-03-30 06:49:35 +00:00
jdata = request . json
2015-12-13 09:34:12 +00:00
domain_name = jdata [ ' domain ' ]
d = Domain ( )
result = d . update_from_master ( domain_name )
if result [ ' status ' ] == ' ok ' :
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : result [ ' msg ' ] } ) , 200 )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : result [ ' msg ' ] } ) , 500 )
except :
2018-03-31 01:21:02 +00:00
logging . error ( traceback . print_exc ( ) )
2015-12-13 09:34:12 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Error when applying new changes ' } ) , 500 )
2018-03-30 23:52:14 +00:00
@app.route ( ' /domain/<path:domain_name>/record/<path:record_name>/type/<path:record_type>/delete ' , methods = [ ' GET ' ] )
2015-12-13 09:34:12 +00:00
@login_required
@admin_role_required
def record_delete ( domain_name , record_name , record_type ) :
try :
r = Record ( name = record_name , type = record_type )
result = r . delete ( domain = domain_name )
if result [ ' status ' ] == ' error ' :
2018-03-30 06:49:35 +00:00
print ( result [ ' msg ' ] )
2015-12-13 09:34:12 +00:00
except :
2018-03-31 01:21:02 +00:00
logging . error ( traceback . print_exc ( ) )
2016-08-05 08:20:41 +00:00
return redirect ( url_for ( ' error ' , code = 500 ) ) , 500
2015-12-13 09:34:12 +00:00
return redirect ( url_for ( ' domain ' , domain_name = domain_name ) )
2018-03-30 23:52:14 +00:00
@app.route ( ' /domain/<path:domain_name>/dnssec ' , methods = [ ' GET ' ] )
2018-03-31 00:32:46 +00:00
@can_access_domain
2016-03-24 13:01:08 +00:00
@login_required
def domain_dnssec ( domain_name ) :
domain = Domain ( )
dnssec = domain . get_domain_dnssec ( domain_name )
return make_response ( jsonify ( dnssec ) , 200 )
2018-03-30 06:49:35 +00:00
2018-03-30 23:52:14 +00:00
@app.route ( ' /domain/<path:domain_name>/managesetting ' , methods = [ ' GET ' , ' POST ' ] )
2016-07-02 17:24:13 +00:00
@login_required
@admin_role_required
def admin_setdomainsetting ( domain_name ) :
if request . method == ' POST ' :
#
# post data should in format
# {'action': 'set_setting', 'setting': 'default_action, 'value': 'True'}
#
try :
2018-03-30 06:49:35 +00:00
jdata = request . json
2016-07-02 17:24:13 +00:00
data = jdata [ ' data ' ]
2018-03-30 06:49:35 +00:00
2016-07-02 17:24:13 +00:00
if jdata [ ' action ' ] == ' set_setting ' :
new_setting = data [ ' setting ' ]
2016-07-03 04:30:16 +00:00
new_value = str ( data [ ' value ' ] )
2016-07-02 17:24:13 +00:00
domain = Domain . query . filter ( Domain . name == domain_name ) . first ( )
setting = DomainSetting . query . filter ( DomainSetting . domain == domain ) . filter ( DomainSetting . setting == new_setting ) . first ( )
2016-08-05 08:20:41 +00:00
2016-07-02 17:24:13 +00:00
if setting :
if setting . set ( new_value ) :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Setting {0} changed value to {1} for {2} ' . format ( new_setting , new_value , domain . name ) , created_by = current_user . username )
2016-07-02 17:24:13 +00:00
history . add ( )
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' Setting updated. ' } ) )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Unable to set value of setting. ' } ) )
else :
if domain . add_setting ( new_setting , new_value ) :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' New setting {0} with value {1} for {2} has been created ' . format ( new_setting , new_value , domain . name ) , created_by = current_user . username )
2016-07-02 17:24:13 +00:00
history . add ( )
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' New setting created and updated. ' } ) )
else :
2016-08-05 08:20:41 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Unable to create new setting. ' } ) )
2016-07-02 17:24:13 +00:00
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Action not supported. ' } ) , 400 )
except :
2018-03-31 01:21:02 +00:00
logging . error ( traceback . print_exc ( ) )
2016-07-02 17:24:13 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' There is something wrong, please contact Administrator. ' } ) , 400 )
2016-03-24 13:01:08 +00:00
2018-01-22 15:22:19 +00:00
@app.route ( ' /templates ' , methods = [ ' GET ' , ' POST ' ] )
@app.route ( ' /templates/list ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_role_required
def templates ( ) :
templates = DomainTemplate . query . all ( )
return render_template ( ' template.html ' , templates = templates )
@app.route ( ' /template/create ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_role_required
def create_template ( ) :
if request . method == ' GET ' :
return render_template ( ' template_add.html ' )
if request . method == ' POST ' :
try :
name = request . form . getlist ( ' name ' ) [ 0 ]
description = request . form . getlist ( ' description ' ) [ 0 ]
if ' ' in name or not name or not type :
flash ( " Please correct your input " , ' error ' )
return redirect ( url_for ( ' create_template ' ) )
if DomainTemplate . query . filter ( DomainTemplate . name == name ) . first ( ) :
2018-04-01 00:57:41 +00:00
flash ( " A template with the name {0} already exists! " . format ( name ) , ' error ' )
2018-01-22 15:22:19 +00:00
return redirect ( url_for ( ' create_template ' ) )
t = DomainTemplate ( name = name , description = description )
result = t . create ( )
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Add domain template {0} ' . format ( name ) , detail = str ( { ' name ' : name , ' description ' : description } ) , created_by = current_user . username )
2018-01-22 15:22:19 +00:00
history . add ( )
return redirect ( url_for ( ' templates ' ) )
else :
flash ( result [ ' msg ' ] , ' error ' )
return redirect ( url_for ( ' create_template ' ) )
2018-03-31 01:21:02 +00:00
except :
logging . error ( traceback . print_exc ( ) )
2018-01-22 15:22:19 +00:00
return redirect ( url_for ( ' error ' , code = 500 ) )
return redirect ( url_for ( ' templates ' ) )
2018-01-23 15:23:21 +00:00
@app.route ( ' /template/createfromzone ' , methods = [ ' POST ' ] )
@login_required
@admin_role_required
def create_template_from_zone ( ) :
try :
2018-03-31 01:21:02 +00:00
jdata = request . json
2018-01-23 15:23:21 +00:00
name = jdata [ ' name ' ]
description = jdata [ ' description ' ]
domain_name = jdata [ ' domain ' ]
if ' ' in name or not name or not type :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Please correct template name ' } ) , 500 )
if DomainTemplate . query . filter ( DomainTemplate . name == name ) . first ( ) :
2018-04-01 00:57:41 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' A template with the name {0} already exists! ' . format ( name ) } ) , 500 )
2018-01-23 15:23:21 +00:00
t = DomainTemplate ( name = name , description = description )
result = t . create ( )
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Add domain template {0} ' . format ( name ) , detail = str ( { ' name ' : name , ' description ' : description } ) , created_by = current_user . username )
2018-01-23 15:23:21 +00:00
history . add ( )
records = [ ]
r = Record ( )
domain = Domain . query . filter ( Domain . name == domain_name ) . first ( )
if domain :
# query domain info from PowerDNS API
zone_info = r . get_record_data ( domain . name )
if zone_info :
jrecords = zone_info [ ' records ' ]
if NEW_SCHEMA :
for jr in jrecords :
name = ' @ ' if jr [ ' name ' ] == domain_name else jr [ ' name ' ]
if jr [ ' type ' ] in app . config [ ' RECORDS_ALLOW_EDIT ' ] :
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 ' ] )
records . append ( record )
else :
for jr in jrecords :
if jr [ ' type ' ] in app . config [ ' RECORDS_ALLOW_EDIT ' ] :
record = DomainTemplateRecord ( name = name , type = jr [ ' type ' ] , status = True if jr [ ' disabled ' ] else False , ttl = jr [ ' ttl ' ] , data = jr [ ' content ' ] )
records . append ( record )
result_records = t . replace_records ( records )
if result_records [ ' status ' ] == ' ok ' :
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : result [ ' msg ' ] } ) , 200 )
else :
result = t . delete_template ( )
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : result_records [ ' msg ' ] } ) , 500 )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : result [ ' msg ' ] } ) , 500 )
2018-03-31 01:21:02 +00:00
except :
logging . error ( traceback . print_exc ( ) )
2018-01-23 15:23:21 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Error when applying new changes ' } ) , 500 )
2018-01-22 15:22:19 +00:00
@app.route ( ' /template/<string:template>/edit ' , methods = [ ' GET ' ] )
@login_required
@admin_role_required
def edit_template ( template ) :
try :
t = DomainTemplate . query . filter ( DomainTemplate . name == template ) . first ( )
if t is not None :
records = [ ]
for jr in t . records :
if jr . type in app . config [ ' RECORDS_ALLOW_EDIT ' ] :
record = DomainTemplateRecord ( name = jr . name , type = jr . type , status = ' Disabled ' if jr . status else ' Active ' , ttl = jr . ttl , data = jr . data )
records . append ( record )
return render_template ( ' template_edit.html ' , template = t . name , records = records , editable_records = app . config [ ' RECORDS_ALLOW_EDIT ' ] )
2018-03-31 01:21:02 +00:00
except :
logging . error ( traceback . print_exc ( ) )
2018-01-22 15:22:19 +00:00
return redirect ( url_for ( ' error ' , code = 500 ) )
return redirect ( url_for ( ' templates ' ) )
@app.route ( ' /template/<string:template>/apply ' , methods = [ ' POST ' ] , strict_slashes = False )
@login_required
def apply_records ( template ) :
try :
2018-03-31 01:21:02 +00:00
jdata = request . json
2018-01-22 15:22:19 +00:00
records = [ ]
for j in jdata :
name = ' @ ' if j [ ' record_name ' ] in [ ' @ ' , ' ' ] else j [ ' record_name ' ]
type = j [ ' record_type ' ]
data = j [ ' record_data ' ]
disabled = True if j [ ' record_status ' ] == ' Disabled ' else False
ttl = int ( j [ ' record_ttl ' ] ) if j [ ' record_ttl ' ] else 3600
dtr = DomainTemplateRecord ( name = name , type = type , data = data , status = disabled , ttl = ttl )
records . append ( dtr )
t = DomainTemplate . query . filter ( DomainTemplate . name == template ) . first ( )
result = t . replace_records ( records )
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Apply domain template record changes to domain template {0} ' . format ( template ) , detail = str ( jdata ) , created_by = current_user . username )
2018-01-22 15:22:19 +00:00
history . add ( )
return make_response ( jsonify ( result ) , 200 )
else :
return make_response ( jsonify ( result ) , 400 )
except :
2018-03-31 01:21:02 +00:00
logging . error ( traceback . print_exc ( ) )
2018-01-22 15:22:19 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Error when applying new changes ' } ) , 500 )
@app.route ( ' /template/<string:template>/delete ' , methods = [ ' GET ' ] )
@login_required
@admin_role_required
def delete_template ( template ) :
try :
t = DomainTemplate . query . filter ( DomainTemplate . name == template ) . first ( )
if t is not None :
result = t . delete_template ( )
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Deleted domain template {0} ' . format ( template ) , detail = str ( { ' name ' : template } ) , created_by = current_user . username )
2018-01-22 15:22:19 +00:00
history . add ( )
return redirect ( url_for ( ' templates ' ) )
else :
flash ( result [ ' msg ' ] , ' error ' )
return redirect ( url_for ( ' templates ' ) )
2018-03-31 01:21:02 +00:00
except :
logging . error ( traceback . print_exc ( ) )
2018-01-22 15:22:19 +00:00
return redirect ( url_for ( ' error ' , code = 500 ) )
return redirect ( url_for ( ' templates ' ) )
2015-12-13 09:34:12 +00:00
@app.route ( ' /admin ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_role_required
def admin ( ) :
domains = Domain . query . all ( )
users = User . query . all ( )
2016-08-05 08:20:41 +00:00
2015-12-13 09:34:12 +00:00
server = Server ( server_id = ' localhost ' )
configs = server . get_config ( )
statistics = server . get_statistic ( )
history_number = History . query . count ( )
2016-08-05 08:20:41 +00:00
2015-12-13 09:34:12 +00:00
if statistics :
2018-03-30 06:49:35 +00:00
uptime = list ( [ uptime for uptime in statistics if uptime [ ' name ' ] == ' uptime ' ] ) [ 0 ] [ ' value ' ]
2015-12-13 09:34:12 +00:00
else :
uptime = 0
return render_template ( ' admin.html ' , domains = domains , users = users , configs = configs , statistics = statistics , uptime = uptime , history_number = history_number )
2018-03-30 06:49:35 +00:00
2016-05-15 20:29:15 +00:00
@app.route ( ' /admin/user/create ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_role_required
def admin_createuser ( ) :
if request . method == ' GET ' :
return render_template ( ' admin_createuser.html ' )
2016-08-05 08:20:41 +00:00
2016-05-15 20:29:15 +00:00
if request . method == ' POST ' :
fdata = request . form
2016-08-05 08:20:41 +00:00
2016-05-15 20:29:15 +00:00
user = User ( username = fdata [ ' username ' ] , plain_text_password = fdata [ ' password ' ] , firstname = fdata [ ' firstname ' ] , lastname = fdata [ ' lastname ' ] , email = fdata [ ' email ' ] )
2016-08-05 08:20:41 +00:00
2016-05-15 20:29:15 +00:00
if fdata [ ' password ' ] == " " :
return render_template ( ' admin_createuser.html ' , user = user , blank_password = True )
2016-08-05 08:20:41 +00:00
2016-05-15 20:29:15 +00:00
result = user . create_local_user ( ) ;
2018-03-30 10:43:34 +00:00
if result [ ' status ' ] :
return redirect ( url_for ( ' admin_manageuser ' ) )
2016-08-05 08:20:41 +00:00
2018-03-30 10:43:34 +00:00
return render_template ( ' admin_createuser.html ' , user = user , error = result [ ' msg ' ] )
2015-12-13 09:34:12 +00:00
2018-03-30 06:49:35 +00:00
2015-12-13 09:34:12 +00:00
@app.route ( ' /admin/manageuser ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_role_required
def admin_manageuser ( ) :
if request . method == ' GET ' :
2016-05-15 20:29:15 +00:00
users = User . query . order_by ( User . username ) . all ( )
2015-12-13 09:34:12 +00:00
return render_template ( ' admin_manageuser.html ' , users = users )
if request . method == ' POST ' :
#
# post data should in format
# {'action': 'delete_user', 'data': 'username'}
#
try :
2018-03-30 06:49:35 +00:00
jdata = request . json
2015-12-13 09:34:12 +00:00
data = jdata [ ' data ' ]
if jdata [ ' action ' ] == ' delete_user ' :
user = User ( username = data )
result = user . delete ( )
if result :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Delete username {0} ' . format ( data ) , created_by = current_user . username )
2015-12-13 09:34:12 +00:00
history . add ( )
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' User has been removed. ' } ) , 200 )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Cannot remove user. ' } ) , 500 )
2016-08-05 08:20:41 +00:00
2015-12-13 09:34:12 +00:00
elif jdata [ ' action ' ] == ' revoke_user_privielges ' :
user = User ( username = data )
result = user . revoke_privilege ( )
if result :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Revoke {0} user privielges ' . format ( data ) , created_by = current_user . username )
2015-12-13 09:34:12 +00:00
history . add ( )
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' Revoked user privielges. ' } ) , 200 )
else :
2016-08-05 08:20:41 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Cannot revoke user privilege. ' } ) , 500 )
2015-12-13 09:34:12 +00:00
elif jdata [ ' action ' ] == ' set_admin ' :
username = data [ ' username ' ]
is_admin = data [ ' is_admin ' ]
user = User ( username = username )
result = user . set_admin ( is_admin )
if result :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' Change user role of {0} ' . format ( username ) , created_by = current_user . username )
2015-12-13 09:34:12 +00:00
history . add ( )
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' Changed user role successfully. ' } ) , 200 )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Cannot change user role. ' } ) , 500 )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Action not supported. ' } ) , 400 )
except :
2018-03-31 01:21:02 +00:00
logging . error ( traceback . print_exc ( ) )
2015-12-13 09:34:12 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' There is something wrong, please contact Administrator. ' } ) , 400 )
@app.route ( ' /admin/history ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
@admin_role_required
def admin_history ( ) :
if request . method == ' POST ' :
h = History ( )
result = h . remove_all ( )
if result :
history = History ( msg = ' Remove all histories ' , created_by = current_user . username )
history . add ( )
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' Changed user role successfully. ' } ) , 200 )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Can not remove histories. ' } ) , 500 )
2016-08-05 08:20:41 +00:00
if request . method == ' GET ' :
2015-12-13 09:34:12 +00:00
histories = History . query . all ( )
return render_template ( ' admin_history.html ' , histories = histories )
2018-03-30 06:49:35 +00:00
2016-04-29 21:36:37 +00:00
@app.route ( ' /admin/settings ' , methods = [ ' GET ' ] )
@login_required
@admin_role_required
def admin_settings ( ) :
2016-08-05 08:20:41 +00:00
if request . method == ' GET ' :
2016-04-29 21:36:37 +00:00
settings = Setting . query . filter ( Setting . name != ' maintenance ' )
return render_template ( ' admin_settings.html ' , settings = settings )
2016-08-05 08:20:41 +00:00
2018-03-30 06:49:35 +00:00
2018-03-30 23:52:14 +00:00
@app.route ( ' /admin/setting/<path:setting>/toggle ' , methods = [ ' POST ' ] )
2016-04-29 21:36:37 +00:00
@login_required
@admin_role_required
def admin_settings_toggle ( setting ) :
result = Setting ( ) . toggle ( setting )
if ( result ) :
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' Toggled setting successfully. ' } ) , 200 )
else :
2016-05-15 18:47:02 +00:00
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Unable to toggle setting. ' } ) , 500 )
2015-12-13 09:34:12 +00:00
2018-03-30 06:49:35 +00:00
2018-03-30 23:52:14 +00:00
@app.route ( ' /admin/setting/<path:setting>/edit ' , methods = [ ' POST ' ] )
2016-06-09 01:23:08 +00:00
@login_required
@admin_role_required
def admin_settings_edit ( setting ) :
2018-03-30 06:49:35 +00:00
jdata = request . json
2016-06-09 01:23:08 +00:00
new_value = jdata [ ' value ' ]
result = Setting ( ) . set ( setting , new_value )
2018-03-30 06:49:35 +00:00
2016-06-09 01:23:08 +00:00
if ( result ) :
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' Toggled setting successfully. ' } ) , 200 )
else :
return make_response ( jsonify ( { ' status ' : ' error ' , ' msg ' : ' Unable to toggle setting. ' } ) , 500 )
2018-03-30 06:49:35 +00:00
2015-12-16 07:21:30 +00:00
@app.route ( ' /user/profile ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def user_profile ( ) :
if request . method == ' GET ' :
return render_template ( ' user_profile.html ' )
if request . method == ' POST ' :
2015-12-16 17:50:28 +00:00
# get new profile info
2015-12-16 07:21:30 +00:00
firstname = request . form [ ' firstname ' ] if ' firstname ' in request . form else ' '
lastname = request . form [ ' lastname ' ] if ' lastname ' in request . form else ' '
email = request . form [ ' email ' ] if ' email ' in request . form else ' '
2015-12-16 17:50:28 +00:00
new_password = request . form [ ' password ' ] if ' password ' in request . form else ' '
2015-12-16 07:21:30 +00:00
2016-06-16 08:33:05 +00:00
# json data
if request . data :
2018-03-30 06:49:35 +00:00
jdata = request . json
2016-06-16 08:33:05 +00:00
data = jdata [ ' data ' ]
if jdata [ ' action ' ] == ' enable_otp ' :
enable_otp = data [ ' enable_otp ' ]
user = User ( username = current_user . username )
user . update_profile ( enable_otp = enable_otp )
2018-04-01 00:57:41 +00:00
return make_response ( jsonify ( { ' status ' : ' ok ' , ' msg ' : ' Change OTP Authentication successfully. Status: {0} ' . format ( enable_otp ) } ) , 200 )
2016-06-16 08:33:05 +00:00
2015-12-16 17:50:28 +00:00
# get new avatar
save_file_name = None
if ' file ' in request . files :
file = request . files [ ' file ' ]
if file :
filename = secure_filename ( file . filename )
file_extension = filename . rsplit ( ' . ' , 1 ) [ 1 ]
2016-08-05 08:20:41 +00:00
if file_extension . lower ( ) in [ ' jpg ' , ' jpeg ' , ' png ' ] :
save_file_name = current_user . username + ' . ' + file_extension
2015-12-16 17:50:28 +00:00
file . save ( os . path . join ( app . config [ ' UPLOAD_DIR ' ] , ' avatar ' , save_file_name ) )
# update user profile
user = User ( username = current_user . username , plain_text_password = new_password , firstname = firstname , lastname = lastname , email = email , avatar = save_file_name , reload_info = False )
2015-12-16 07:21:30 +00:00
user . update_profile ( )
2015-12-16 17:50:28 +00:00
2015-12-16 07:21:30 +00:00
return render_template ( ' user_profile.html ' )
2015-12-16 17:50:28 +00:00
2018-03-30 23:52:14 +00:00
@app.route ( ' /user/avatar/<path:filename> ' )
2015-12-16 17:50:28 +00:00
def user_avatar ( filename ) :
return send_from_directory ( os . path . join ( app . config [ ' UPLOAD_DIR ' ] , ' avatar ' ) , filename )
2016-06-16 08:33:05 +00:00
@app.route ( ' /qrcode ' )
@login_required
def qrcode ( ) :
if not current_user :
return redirect ( url_for ( ' index ' ) )
# render qrcode for FreeTOTP
2016-09-17 13:41:22 +00:00
img = qrc . make ( current_user . get_totp_uri ( ) , image_factory = qrc_svg . SvgImage )
2016-06-16 08:33:05 +00:00
stream = BytesIO ( )
2016-09-17 13:41:22 +00:00
img . save ( stream )
2016-06-16 08:33:05 +00:00
return stream . getvalue ( ) , 200 , {
' Content-Type ' : ' image/svg+xml ' ,
' Cache-Control ' : ' no-cache, no-store, must-revalidate ' ,
' Pragma ' : ' no-cache ' ,
' Expires ' : ' 0 ' }
2016-06-20 09:32:14 +00:00
@app.route ( ' /nic/checkip.html ' , methods = [ ' GET ' , ' POST ' ] )
def dyndns_checkip ( ) :
# route covers the default ddclient 'web' setting for the checkip service
2016-07-01 22:02:37 +00:00
return render_template ( ' dyndns.html ' , response = request . environ . get ( ' HTTP_X_REAL_IP ' , request . remote_addr ) )
2016-06-20 09:32:14 +00:00
2018-03-30 06:49:35 +00:00
2016-06-20 09:32:14 +00:00
@app.route ( ' /nic/update ' , methods = [ ' GET ' , ' POST ' ] )
@dyndns_login_required
def dyndns_update ( ) :
# dyndns protocol response codes in use are:
# good: update successful
# nochg: IP address already set to update address
# nohost: hostname does not exist for this user account
# 911: server error
# have to use 200 HTTP return codes because ddclient does not read the return string if the code is other than 200
# reference: https://help.dyn.com/remote-access-api/perform-update/
# reference: https://help.dyn.com/remote-access-api/return-codes/
hostname = request . args . get ( ' hostname ' )
myip = request . args . get ( ' myip ' )
try :
# get all domains owned by the current user
domains = User ( id = current_user . id ) . get_domain ( )
except :
return render_template ( ' dyndns.html ' , response = ' 911 ' ) , 200
2016-08-05 08:20:41 +00:00
2016-07-02 17:24:13 +00:00
domain = None
domain_segments = hostname . split ( ' . ' )
for index in range ( len ( domain_segments ) ) :
domain_segments . pop ( 0 )
full_domain = ' . ' . join ( domain_segments )
potential_domain = Domain . query . filter ( Domain . name == full_domain ) . first ( )
if potential_domain in domains :
domain = potential_domain
break
2016-08-05 08:20:41 +00:00
2016-07-02 17:24:13 +00:00
if not domain :
2018-04-01 00:57:41 +00:00
history = History ( msg = " DynDNS update: attempted update of {0} but it does not exist for this user " . format ( hostname ) , created_by = current_user . username )
2016-07-02 17:24:13 +00:00
history . add ( )
return render_template ( ' dyndns.html ' , response = ' nohost ' ) , 200
2016-08-05 08:20:41 +00:00
2016-07-02 17:24:13 +00:00
r = Record ( )
r . name = hostname
# check if the user requested record exists within this domain
2018-01-23 09:08:50 +00:00
if r . exists ( domain . name ) and r . is_allowed_edit ( ) :
2016-07-02 17:24:13 +00:00
if r . data == myip :
# record content did not change, return 'nochg'
2018-04-01 00:57:41 +00:00
history = History ( msg = " DynDNS update: attempted update of {0} but record did not change " . format ( hostname ) , created_by = current_user . username )
2016-07-02 17:24:13 +00:00
history . add ( )
return render_template ( ' dyndns.html ' , response = ' nochg ' ) , 200
else :
oldip = r . data
result = r . update ( domain . name , myip )
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' DynDNS update: updated record {0} in zone {1} , it changed from {2} to {3} ' . format ( hostname , domain . name , oldip , myip ) , detail = str ( result ) , created_by = current_user . username )
2016-06-20 09:32:14 +00:00
history . add ( )
2016-07-02 17:24:13 +00:00
return render_template ( ' dyndns.html ' , response = ' good ' ) , 200
2016-06-20 09:32:14 +00:00
else :
2016-07-02 17:24:13 +00:00
return render_template ( ' dyndns.html ' , response = ' 911 ' ) , 200
2018-01-23 09:08:50 +00:00
elif r . is_allowed_edit ( ) :
2016-07-02 17:24:13 +00:00
ondemand_creation = DomainSetting . query . filter ( DomainSetting . domain == domain ) . filter ( DomainSetting . setting == ' create_via_dyndns ' ) . first ( )
2016-07-03 18:42:14 +00:00
if ( ondemand_creation != None ) and ( strtobool ( ondemand_creation . value ) == True ) :
2016-07-03 00:36:21 +00:00
record = Record ( name = hostname , type = ' A ' , data = myip , status = False , ttl = 3600 )
2016-07-02 17:24:13 +00:00
result = record . add ( domain . name )
if result [ ' status ' ] == ' ok ' :
2018-04-01 00:57:41 +00:00
history = History ( msg = ' DynDNS update: created record {0} in zone {1} , it now represents {2} ' . format ( hostname , domain . name , myip ) , detail = str ( result ) , created_by = current_user . username )
2016-07-02 17:24:13 +00:00
history . add ( )
return render_template ( ' dyndns.html ' , response = ' good ' ) , 200
2016-08-05 08:20:41 +00:00
2018-04-01 00:57:41 +00:00
history = History ( msg = ' DynDNS update: attempted update of {0} but it does not exist for this user ' . format ( hostname ) , created_by = current_user . username )
2016-06-20 09:32:14 +00:00
history . add ( )
return render_template ( ' dyndns.html ' , response = ' nohost ' ) , 200
2015-12-13 09:34:12 +00:00
@app.route ( ' / ' , methods = [ ' GET ' , ' POST ' ] )
@login_required
def index ( ) :
2016-08-05 08:20:41 +00:00
return redirect ( url_for ( ' dashboard ' ) )
2015-12-13 09:34:12 +00:00
# END VIEWS