Ejemplo n.º 1
0
def active_action(session_id, action):
    provider = Provider()
    sessions = provider.sessions()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    if action not in ['show', 'hide']:
        flash('Invalid Action', 'error')
        return redirect(url_for('home.index'))

    active = True if action == 'show' else False
    sessions.set_active(session_id, active)

    flash('Session updated', 'success')
    return redirect(url_for('home.index'))
Ejemplo n.º 2
0
def setup_mask_save(session_id):
    provider = Provider()
    sessions = provider.sessions()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    mask = request.form['compiled-mask'].strip()
    enable_increments = int(request.form.get('enable_increments', 0))
    if enable_increments == 1:
        increment_min = int(request.form['increment-min'].strip())
        increment_max = int(request.form['increment-max'].strip())
    else:
        increment_min = 0
        increment_max = 0

    has_errors = False
    if len(mask) == 0:
        flash('No mask set', 'error')
        has_errors = True

    if enable_increments == 1:
        if increment_min <= 0:
            has_errors = True
            flash('Min Increment is invalid', 'error')

        if increment_max <= 0:
            has_errors = True
            flash('Max Increment is invalid', 'error')

        if increment_min > increment_max:
            has_errors = True
            flash('Min Increment cannot be bigger than Max Increment', 'error')
    else:
        increment_min = 0
        increment_max = 0

    if has_errors:
        return redirect(url_for('sessions.setup_mask', session_id=session_id))

    sessions.set_hashcat_setting(session_id, 'mask', mask)
    sessions.set_hashcat_setting(session_id, 'increment_min', increment_min)
    sessions.set_hashcat_setting(session_id, 'increment_max', increment_max)

    return redirect(url_for('sessions.settings', session_id=session_id))
Ejemplo n.º 3
0
def system_messages_save():
    if not current_user.admin:
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    provider = Provider()
    settings = provider.settings()

    system_message_login = request.form['system_message_login'].strip()
    system_message_login_show = int(
        request.form.get('system_message_login_show', 0))

    settings.save('system_message_login', system_message_login)
    settings.save('system_message_login_show', system_message_login_show)

    flash('Settings saved', 'success')
    return redirect(url_for('admin.system_messages'))
Ejemplo n.º 4
0
def setup_wordlist(session_id):
    provider = Provider()
    sessions = provider.sessions()
    wordlists = provider.wordlists()
    rules = provider.rules()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    user_id = 0 if current_user.admin else current_user.id
    session = sessions.get(user_id=user_id, session_id=session_id)[0]

    return render_template('sessions/setup/wordlist.html',
                           session=session,
                           wordlists=wordlists.get_wordlists(),
                           rules=rules.get_rules())
Ejemplo n.º 5
0
    def delete(self, user_id, id, zone_id=None, domain=None):
        provider = Provider()
        zones = provider.dns_zones()
        restrictions = provider.dns_restrictions()

        zone = zones.get(zone_id,
                         user_id) if zone_id is not None else zones.find(
                             domain, user_id=user_id)
        if not zone:
            return self.send_not_found_response()

        restriction = restrictions.find(id=id, zone_id=zone.id)
        if not restriction:
            return self.send_not_found_response()

        restriction.delete()
        return self.send_success_response()
Ejemplo n.º 6
0
def login_2fa_process():
    next = urllib.parse.unquote_plus(request.args.get('next', '').strip())
    otp = request.form['otp'].strip()

    provider = Provider()
    users = provider.users()

    id = int(session['otp_userid']) if 'otp_userid' in session else 0
    otp_time = int(session['otp_time']) if 'otp_time' in session else 0

    can_continue = True
    if id <= 0:
        can_continue = False
    elif int(time.time()) > (otp_time + 120):
        # This page is valid for 2 minutes.
        can_continue = False

    if not can_continue:
        session.pop('otp_userid', None)
        session.pop('otp_time', None)

        return redirect(url_for('auth.login', next=next))

    user = users.get_user(id)
    if not user:
        return redirect(url_for('auth.login', next=next))

    if not users.otp_verify_user(user, otp):
        flash('Invalid Code', 'error')
        return redirect(url_for('auth.login_2fa', next=next))

    session.pop('otp_userid', None)
    session.pop('otp_time', None)

    # If we reach this point it means that our user exists. Check if the user is active.
    user = users.login_session(user)
    login_user(user)

    # On every login we get the hashcat version and the git hash version.
    system = provider.system()
    system.run_updates()

    if next and url_parse(next).netloc == '':
        return redirect(next)

    return redirect(url_for('home.index'))
Ejemplo n.º 7
0
def settings_auth_save_general():
    if not current_user.admin:
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    provider = Provider()
    settings = provider.settings()

    allow_logins = request.form.get('allow_logins', 0)
    settings.save('allow_logins', allow_logins)

    # When settings are saved, run system updates.
    system = provider.system()
    system.run_updates()

    flash('Settings saved', 'success')
    return redirect(url_for('admin.settings_auth'))
Ejemplo n.º 8
0
def ldap_changepwd_process():
    provider = Provider()
    users = provider.users()
    ldap = provider.ldap()

    next = urllib.parse.unquote_plus(request.args.get('next', '').strip())
    password = request.form['password'].strip()
    new_password = request.form['new_password'].strip()
    confirm_password = request.form['confirm_password'].strip()

    username = session['ldap_username'] if 'ldap_username' in session else ''
    ldap_time = session['ldap_time'] if 'ldap_time' in session else 0
    if len(username) == 0:
        session.pop('ldap_username', None)
        session.pop('ldap_time', None)
        return redirect(url_for('auth.login', next=next))
    elif int(time.time()) > (ldap_time + 120):
        session.pop('ldap_username', None)
        session.pop('ldap_time', None)
        return redirect(url_for('auth.login', next=next))

    user = users.get_ldap_user(username)
    if not user:
        session.pop('ldap_username', None)
        session.pop('ldap_time', None)
        return redirect(url_for('auth.login', next=next))

    if len(password) == 0:
        flash('Please enter your current password', 'error')
        return redirect(url_for('ldap_changepwd', next=next))
    elif len(new_password) == 0 or len(confirm_password) == 0:
        flash('Please enter your new password', 'error')
        return redirect(url_for('ldap_changepwd', next=next))
    elif new_password != confirm_password:
        flash('New passwords do not match', 'error')
        return redirect(url_for('ldap_changepwd', next=next))

    session.pop('ldap_username', None)
    session.pop('ldap_time', None)

    if not ldap.update_password_ad(user.username, password, new_password):
        flash('Could not update password', 'error')
        return redirect(url_for('auth.login', next=next))

    flash('Password updated - please login again', 'success')
    return redirect(url_for('auth.login', next=next))
Ejemplo n.º 9
0
def cli_users_add(username, password, full_name, email, active, admin, ldap,
                  create_zone):
    provider = Provider()
    users = provider.users()
    zones = provider.dns_zones()

    active = (active in ['true', 'yes'])
    admin = (admin in ['true', 'yes'])
    ldap = (ldap in ['true', 'yes'])

    ask_for_password = False
    if len(password) == 0:
        # If it's an LDAP user, we don't need it.
        if not ldap:
            ask_for_password = True

    if ask_for_password:
        password = click.prompt('Password',
                                hide_input=True,
                                confirmation_prompt=True)

    # If the user entered the password manually it's in plaintext so we can check for complexity.
    user = users.save(0,
                      username,
                      password,
                      full_name,
                      email,
                      admin,
                      ldap,
                      active,
                      check_complexity=ask_for_password,
                      hash_password=ask_for_password)
    if not user:
        print(users.last_error)
        return False

    if create_zone:
        if not zones.create_user_base_zone(user):
            print(
                'User has been created but there was a problem creating their base domain. Make sure the DNS Base Domain has been set.'
            )
            return False

    print("User created")
    return True
Ejemplo n.º 10
0
def user_save(user_id):
    username = request.form['username'].strip() if 'username' in request.form else ''
    password = request.form['password'].strip() if 'password' in request.form else ''
    full_name = request.form['full_name'].strip() if 'full_name' in request.form else ''
    email = request.form['email'].strip() if 'email' in request.form else ''
    admin = int(request.form.get('admin', 0))
    ldap = int(request.form.get('ldap', 0))
    active = int(request.form.get('active', 0))

    provider = Provider()
    users = provider.users()

    if not users.save(user_id, username, password, full_name, email, admin, ldap, active):
        flash(users.get_last_error(), 'error')
        return redirect(url_for('admin.user_edit', user_id=user_id))

    flash('User saved', 'success')
    return redirect(url_for('config.users'))
Ejemplo n.º 11
0
    def download(self, user_id, session_id):
        required_fields = ['type']
        data = self.get_json(required_fields)
        if data is False:
            return self.send_error_response(
                5000, 'Missing fields',
                'Required fields are: ' + ', '.join(required_fields))

        provider = Provider()
        sessions = provider.sessions()

        session = sessions.get(user_id=user_id, session_id=session_id)
        if not session:
            return self.send_access_denied_response()
        elif not data['type'] in ['all', 'plain', 'cracked']:
            return self.send_error_response(5009, 'Invalid download type', '')

        return sessions.download_file(session_id, data['type'])
Ejemplo n.º 12
0
def history_apply(session_id, history_id):
    provider = Provider()
    sessions = provider.sessions()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))
    elif not sessions.can_access_history(current_user, session_id, history_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    if not sessions.restore_hashcat_history(session_id, history_id):
        flash('Could not apply historical settings to the current session',
              'error')
    else:
        flash('Historical settings applied', 'success')

    return redirect(url_for('sessions.view', session_id=session_id))
Ejemplo n.º 13
0
def password_complexity_save():
    pwd_min_length = int(request.form['pwd_min_length'].strip())
    pwd_min_lower = int(request.form['pwd_min_lower'].strip())
    pwd_min_upper = int(request.form['pwd_min_upper'].strip())
    pwd_min_digits = int(request.form['pwd_min_digits'].strip())
    pwd_min_special = int(request.form['pwd_min_special'].strip())

    provider = Provider()
    settings = provider.settings()

    settings.save('pwd_min_length', pwd_min_length)
    settings.save('pwd_min_lower', pwd_min_lower)
    settings.save('pwd_min_upper', pwd_min_upper)
    settings.save('pwd_min_digits', pwd_min_digits)
    settings.save('pwd_min_special', pwd_min_special)

    flash('Settings saved', 'success')
    return redirect(url_for('config.password_complexity'))
Ejemplo n.º 14
0
def zones_import_upload():
    provider = Provider()
    import_manager = provider.dns_import()

    if len(request.files) != 1:
        flash('Uploaded file could not be found', 'error')
        return redirect(url_for('dns.zones_import'))

    file = request.files['csvfile']
    if file.filename == '':
        flash('No file uploaded', 'error')
        return redirect(url_for('dns.zones_import'))

    file.save(
        import_manager.get_user_data_path(current_user.id,
                                          filename='import.csv'))

    return redirect(url_for('dns.zones_import_review'))
Ejemplo n.º 15
0
    def set_mask(self, user_id, session_id):
        required_fields = ['mask']
        data = self.get_json(required_fields)
        if data is False:
            return self.send_error_response(
                5000, 'Missing fields',
                'Required fields are: ' + ', '.join(required_fields))

        provider = Provider()
        sessions = provider.sessions()

        session = sessions.get(user_id=user_id, session_id=session_id)
        if not session:
            return self.send_access_denied_response()

        sessions.set_hashcat_setting(session_id, 'mask', data['mask'])

        return self.send_success_response()
Ejemplo n.º 16
0
def ldap_changepwd():
    provider = Provider()
    users = provider.users()

    next = urllib.parse.unquote_plus(request.args.get('next', '').strip())
    username = session['ldap_username'] if 'ldap_username' in session else ''
    ldap_time = session['ldap_time'] if 'ldap_time' in session else 0

    if len(username) == 0:
        session.pop('ldap_username', None)
        session.pop('ldap_time', None)
        return redirect(url_for('auth.login', next=next))
    elif int(time.time()) > (ldap_time + 120):
        session.pop('ldap_username', None)
        session.pop('ldap_time', None)
        return redirect(url_for('auth.login', next=next))

    return render_template('auth/ldap_password.html', next=request.args.get('next', ''))
Ejemplo n.º 17
0
def __toggle_apikey(id):
    provider = Provider()
    api = provider.api()

    if not api.can_access(id, current_user.id):
        flash('Access Denied', 'error')
        return redirect(url_for('config.api'))

    key = api.get(id)
    if not key:
        flash('Could not retrieve key', 'error')
        return redirect(url_for('config.api'))

    key.enabled = not key.enabled
    key.save()

    flash('API Key status updated', 'success')
    return redirect(url_for('config.api'))
Ejemplo n.º 18
0
def tags_delete(tag_id):
    provider = Provider()
    zones = provider.dns_zones()
    tags = provider.tags()

    user_id = None if current_user.admin else current_user.id
    if not tags.can_access(tag_id, user_id):
        flash('You cannot access the selected tag', 'error')
        return redirect(url_for('dns.tags_index'))

    zones.tag_delete(tag_id)

    if not tags.delete(tag_id, user_id=user_id):
        flash('Could not delete tag', 'error')
        return redirect(url_for('dns.tags_index'))

    flash('Tag deleted', 'success')
    return redirect(url_for('dns.tags_index'))
Ejemplo n.º 19
0
def browse(session_id):
    provider = Provider()
    sessions = provider.sessions()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    user_id = 0 if current_user.admin else current_user.id
    session = sessions.get(user_id=user_id, session_id=session_id)[0]
    if not session.hashcat.contains_usernames:
        return redirect(url_for('sessions.view', session_id=session_id))
    cracked = sessions.get_cracked_passwords(session_id).split("\n")

    return render_template(
        'sessions/browse.html',
        session=session,
        cracked=json.dumps(cracked, indent=4, sort_keys=True, default=str)
    )
Ejemplo n.º 20
0
def setup_hashes(session_id):
    provider = Provider()
    sessions = provider.sessions()
    uploaded_hashes = provider.hashes()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    user_id = 0 if current_user.admin else current_user.id
    session = sessions.get(user_id=user_id, session_id=session_id)[0]

    uploaded_hashfiles = uploaded_hashes.get_uploaded_hashes()

    return render_template(
        'sessions/setup/hashes.html',
        session=session,
        uploaded_hashfiles_json=json.dumps(uploaded_hashfiles, indent=4, sort_keys=True, default=str),
    )
Ejemplo n.º 21
0
def setup_mask(session_id):
    provider = Provider()
    sessions = provider.sessions()
    masks = provider.masks()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    user_id = 0 if current_user.admin else current_user.id
    session = sessions.get(user_id=user_id, session_id=session_id)[0]
    has_custom_masklist = sessions.session_filesystem.custom_file_exists(sessions.session_filesystem.get_custom_file_path(current_user.id, session_id, prefix='custom_masklist', random=False, extension='.hcmask'))

    return render_template(
        'sessions/setup/mask.html',
        session=session,
        masks=masks.get_masks(),
        has_custom_masklist=has_custom_masklist
    )
Ejemplo n.º 22
0
def view(session_id):
    provider = Provider()
    sessions = provider.sessions()
    hashcat = provider.hashcat()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    user_id = 0 if current_user.admin else current_user.id
    session = sessions.get(user_id=user_id, session_id=session_id)[0]

    supported_hashes = hashcat.get_supported_hashes()
    # We need to process the array in a way to make it easy for JSON usage.
    supported_hashes = hashcat.compact_hashes(supported_hashes)

    return render_template('sessions/view.html',
                           session=session,
                           supported_hashes=supported_hashes)
Ejemplo n.º 23
0
def zone_restrictions(dns_zone_id):
    provider = Provider()
    zones = provider.dns_zones()

    if not zones.can_access(dns_zone_id, current_user.id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    zone = zones.get(dns_zone_id)
    if not zone:
        flash('Zone not found', 'error')
        return redirect(url_for('home.index'))

    return render_template(
        'dns/zones/view.html',
        zone=zone,
        section='restrictions',
        tab='restrictions'
    )
Ejemplo n.º 24
0
    def upload(self, user_id, session_id):
        required_fields = ['data']
        data = self.get_json(required_fields)
        if data is False:
            return self.send_error_response(
                5000, 'Missing fields',
                'Required fields are: ' + ', '.join(required_fields))

        provider = Provider()
        sessions = provider.sessions()

        session = sessions.get(user_id=user_id, session_id=session_id)
        if not session:
            return self.send_access_denied_response()

        sessions.session_filesystem.save_hashes(user_id, session_id,
                                                data['data'])

        return self.send_success_response()
Ejemplo n.º 25
0
    def set_custom(self, user_id, session_id):
        required_fields = ['data']
        data = self.get_json(required_fields)
        if data is False:
            return self.send_error_response(5000, 'Missing fields',
                                            'Required fields are: ' + ', '.join(required_fields))

        provider = Provider()
        sessions = provider.sessions()

        session = sessions.get(user_id=user_id, session_id=session_id)
        if not session:
            return self.send_access_denied_response()

        save_as = sessions.session_filesystem.get_custom_file_path(user_id, session_id, prefix='custom_wordlist_', random=True)
        sessions.session_filesystem.write_to_file(save_as, data['data'])
        sessions.set_hashcat_setting(session_id, 'wordlist', save_as)

        return self.send_success_response()
Ejemplo n.º 26
0
    def create(self, user_id):
        required_fields = [
            'domain', 'active', 'catch_all', 'master', 'forwarding', 'regex',
            'tags'
        ]
        data = self.get_json(required_fields)
        if data is False:
            return self.send_error_response(
                5000, 'Missing fields',
                'Required fields are: {0}'.format(', '.join(required_fields)))

        if len(data['domain']) == 0:
            return self.send_error_response(5001, 'Domain cannot be empty.',
                                            '')

        data['active'] = True if data['active'] else False
        data['catch_all'] = True if data['catch_all'] else False
        data['master'] = True if data['master'] else False
        data['forwarding'] = True if data['forwarding'] else False
        data['regex'] = True if data['regex'] else False
        data['tags'] = data['tags'].split(',')

        provider = Provider()
        zones = provider.dns_zones()

        zone = zones.new(data['domain'],
                         data['active'],
                         data['catch_all'],
                         data['forwarding'],
                         data['regex'],
                         user_id,
                         master=data['master'],
                         update_old_logs=True)
        if isinstance(zone, list):
            errors = '\n'.join(zone)
            return self.send_error_response(5003, 'Could not create zone',
                                            errors)

        zone = zones.save_tags(zone, data['tags'])
        if not zone:
            return self.send_error_response(5002, 'Could not save tags', '')

        return self.one(user_id, zone_id=zone.id)
Ejemplo n.º 27
0
def setup_hashcat_save(session_id):
    provider = Provider()
    sessions = provider.sessions()
    hashcat = provider.hashcat()

    if not sessions.can_access(current_user, session_id):
        flash('Access Denied', 'error')
        return redirect(url_for('home.index'))

    hash_type = request.form['hash-type'].strip()
    optimised_kernel = int(request.form.get('optimised_kernel', 0))
    workload = int(request.form.get('workload', 2))
    mode = int(request.form['mode'].strip())

    if mode != 0 and mode != 3:
        # As all the conditions below depend on the mode, if it's wrong return to the previous page immediately.
        flash('Invalid attack mode selected', 'error')
        return redirect(
            url_for('sessions.setup_hashcat', session_id=session_id))
    elif workload not in [1, 2, 3, 4]:
        flash('Invalid workload selected', 'error')
        return redirect(
            url_for('sessions.setup_hashcat', session_id=session_id))

    has_errors = False
    if not hashcat.is_valid_hash_type(hash_type):
        has_errors = True
        flash('Invalid hash type selected', 'error')

    if has_errors:
        return redirect(
            url_for('sessions.setup_hashcat', session_id=session_id))

    sessions.set_hashcat_setting(session_id, 'mode', mode)
    sessions.set_hashcat_setting(session_id, 'hashtype', hash_type)
    sessions.set_hashcat_setting(session_id, 'optimised_kernel',
                                 optimised_kernel)
    sessions.set_hashcat_setting(session_id, 'workload', workload)

    redirect_to = 'wordlist' if mode == 0 else 'mask'

    return redirect(
        url_for('sessions.setup_' + redirect_to, session_id=session_id))
Ejemplo n.º 28
0
    def notifications(self, user_id, session_id):
        required_fields = ['state']
        data = self.get_json(required_fields)
        if data is False:
            return self.send_error_response(
                5000, 'Missing fields',
                'Required fields are: ' + ', '.join(required_fields))

        provider = Provider()
        sessions = provider.sessions()

        session = sessions.get(user_id=user_id, session_id=session_id)
        if not session:
            return self.send_access_denied_response()

        notifications_enabled = True if data['state'] else False
        sessions.set_notifications(session_id, notifications_enabled)

        return self.send_success_response()
Ejemplo n.º 29
0
    def update(self, user_id, id, zone_id=None, domain=None):
        provider = Provider()
        zones = provider.dns_zones()
        restrictions = provider.dns_restrictions()

        zone = zones.get(zone_id,
                         user_id) if zone_id is not None else zones.find(
                             domain, user_id=user_id)
        if not zone:
            return self.send_not_found_response()

        restriction = restrictions.find(id=id, zone_id=zone.id)
        if not restriction:
            return self.send_not_found_response()

        data = self.get_json([])
        if 'enabled' in data:
            data['enabled'] = True if data['enabled'] else False
        else:
            data['enabled'] = restriction.enabled

        if 'type' in data:
            if data['type'] not in ['allow', 'block']:
                return self.send_error_response(5005,
                                                'Invalid restriction type', '')
            data['type'] = 1 if data['type'] == 'allow' else 2
        else:
            data['type'] = restriction.type

        if 'ip_or_range' in data:
            if len(data['ip_or_range']
                   ) == 0 or not restrictions.is_valid_ip_or_range(
                       data['ip_or_range']):
                return self.send_error_response(5005, 'Invalid IP or Range',
                                                '')
        else:
            data['ip_or_range'] = restriction.ip_range

        restriction = restrictions.save(restriction, zone.id,
                                        data['ip_or_range'], data['type'],
                                        data['enabled'])

        return self.one(user_id, restriction.id, zone_id=zone.id)
Ejemplo n.º 30
0
def smtp_save():
    provider = Provider()
    settings = provider.settings()

    smtp_enabled = True if int(request.form.get('smtp_enabled',
                                                0)) == 1 else False
    smtp_host = request.form['smtp_host'].strip()
    smtp_port = int(request.form['smtp_port'].strip())
    smtp_tls = True if int(request.form.get('smtp_tls', 0)) == 1 else False
    smtp_user = request.form['smtp_user'].strip()
    smtp_pass = request.form['smtp_pass'].strip()
    smtp_sender = request.form['smtp_sender'].strip()

    if len(smtp_host) == 0:
        flash('Please enter SMTP Host', 'error')
        return redirect(url_for('config.smtp'))
    elif smtp_port <= 0 or smtp_port > 65535:
        flash('Please enter SMTP Port', 'error')
        return redirect(url_for('config.smtp'))
    elif len(smtp_user) == 0:
        flash('Please enter SMTP User', 'error')
        return redirect(url_for('config.smtp'))
    elif len(smtp_pass) == 0:
        flash('Please enter SMTP Pass', 'error')
        return redirect(url_for('config.smtp'))
    elif smtp_pass == '********' and len(settings.get('smtp_pass', '')) == 0:
        flash('Please enter SMTP Pass', 'error')
        return redirect(url_for('config.smtp'))
    elif len(smtp_sender) == 0:
        flash('Please enter SMTP Sender E-mail', 'error')
        return redirect(url_for('config.smtp'))

    settings.save('smtp_enabled', smtp_enabled)
    settings.save('smtp_host', smtp_host)
    settings.save('smtp_port', smtp_port)
    settings.save('smtp_tls', smtp_tls)
    settings.save('smtp_user', smtp_user)
    settings.save('smtp_sender', smtp_sender)
    if smtp_pass != '********':
        settings.save('smtp_pass', smtp_pass)

    flash('Settings saved', 'success')
    return redirect(url_for('config.smtp'))