import json import os import re from datetime import datetime from flask import Flask, render_template, request, redirect, url_for, flash from flask.views import View, MethodView from flask_login import LoginManager, current_user, login_user, logout_user, login_required from flask_qrcode import QRcode from flask_wtf import CSRFProtect from authentication import User from db import gen_token, modify_user, add_user, enable_user, disable_user, list_users, grant_access, del_user WIFI_SEND_URL = 'http://' + os.environ['LOCK_WIFI_IP'] + '/send/' app = Flask(__name__) app.secret_key = os.environ['FLASK_SECRET_KEY'] QRcode(app) csrf = CSRFProtect(app) login_manager = LoginManager() login_manager.init_app(app) login_manager.login_view = "login" @login_manager.user_loader def load_user(user_id): return User.get(user_id) @app.route('/api/token', methods=['POST']) def api_token(): try: jsn = request.get_json(force=True) if 'key' not in jsn: return app.response_class( response=json.dumps({'error': 'must contain "key" field'}), status=400, mimetype='application/json' ) else: token = gen_token(jsn['key']) if token is not None: return app.response_class( response=json.dumps({'token': token}), status=200, mimetype='application/json' ) else: return app.response_class( response=json.dumps({'error': 'invalid key - access denied'}), status=403, mimetype='application/json' ) except: return app.response_class( response=json.dumps({'error': 'Invalid json'}), status=400, mimetype='application/json' ) @app.route('/login', methods=['GET', 'POST']) def login(): if current_user.is_authenticated: return redirect(url_for('advanced')) if request.method == 'POST': user = User.login(key=request.form.get('secret_key')) if user is None: flash('Invalid username or password') return redirect(url_for('login')) login_user(user) return redirect(url_for('advanced')) else: return render_template('login.html') @app.route('/logout') def logout(): logout_user() return redirect(url_for('index')) @app.route('/access-request', methods=['GET', 'POST']) def access_request(): data = {} if request.method == 'POST': req_id, key = add_user() data['req_id'] = req_id data['key'] = key data['grant_access_link'] = url_for('advanced', req_id=req_id, _external=True) data['is_request'] = True elif request.method == 'GET': data['is_request'] = False return render_template('access_request.html', **data) def _get_user_list(): users = list_users(current_user.key) return { 'users': [ { 'id': user[0], 'req_id': user[1], 'name': user[2], 'valid_from': user[4], 'valid_to': user[5], 'token_validity_time': user[6], 'active': user[7], 'usermod': user[8] } for user in users ] } class AdvancedView(MethodView): decorators = [login_required] def get_template_name(self): return 'advanced.html' def render_template(self): return render_template(self.get_template_name(), **self.get_context()) def get_context(self): users = list_users(current_user.key) return { 'preselect': request.args.get('req_id'), 'users': [ { 'id': user[0], 'req_id': user[1], 'name': user[2], 'valid_from': user[4], 'valid_to': user[5], 'token_validity_time': user[6], 'active': user[7], 'usermod': user[8] } for user in users ] } def get(self): return self.render_template() def post(self): if 'action' not in request.args: return self.render_template() if request.args.get('action') == 'enable_user': res = enable_user(current_user.key, request.form.get('req_id')) elif request.args.get('action') == 'disable_user': res = disable_user(current_user.key, request.form.get('req_id')) elif request.args.get('action') == 'delete_user': res = del_user(current_user.key, request.form.get('req_id')) elif request.args.get('action') == 'modify_user': if re.match(r'^\d{2}/\d{2}/\d{4}$', request.form.get('valid_from_date')): date_pattern = '%m/%d/%Y' elif re.match(r'^\d{4}-\d{2}-\d{2}$', request.form.get('valid_from_date')): date_pattern = '%Y-%m-%d' else: flash('Unknown date format for valid_from/valid_to', category='danger') return self.render_template() valid_from = datetime.strptime( request.form.get('valid_from_date') + ' ' + request.form.get('valid_from_time'), f'{date_pattern} %H:%M:%S') valid_to = datetime.strptime( request.form.get('valid_to_date') + ' ' + request.form.get('valid_to_time'), f'{date_pattern} %H:%M:%S') usermod = request.form.get('usermod') == 'on' res = modify_user(current_user.key, request.form.get('req_id'), request.form.get('username'), valid_from, valid_to, request.form.get('token_validity_time'), usermod)[0] if res is None: flash('Error changing user', category='danger') return self.render_template() elif request.args.get('action') == 'grant_access': if re.match(r'^\d{2}/\d{2}/\d{4}$', request.form.get('valid_from_date')): date_pattern = '%m/%d/%Y' elif re.match(r'^\d{4}-\d{2}-\d{2}$', request.form.get('valid_from_date')): date_pattern = '%Y-%m-%d' else: flash('Unknown date format for valid_from/valid_to', category='danger') return self.render_template() valid_from = datetime.strptime( request.form.get('valid_from_date') + ' ' + request.form.get('valid_from_time'), f'{date_pattern} %H:%M:%S') valid_to = datetime.strptime( request.form.get('valid_to_date') + ' ' + request.form.get('valid_to_time'), f'{date_pattern} %H:%M:%S') res = grant_access(current_user.key, request.form.get('req_id'), request.form.get('username'), valid_from, valid_to, request.form.get('token_validity_time'))[0] if res is None: flash('Error granting access to user', category='danger') return self.render_template() else: flash(f'Unknown action {request.args.get("action")}', category='danger') return self.render_template() if res is None: flash('Error', category='danger') return self.render_template() return self.render_template() @app.route('/', methods=['GET', 'POST']) def index(): if request.method == 'POST': token = gen_token(request.form.get('secret_key')) if token is None: return render_template('error.html', error='DENIED!!!') data = { 'token': token, 'token_url': WIFI_SEND_URL + token } return render_template('access.html', **data) else: return render_template('index.html') app.add_url_rule('/advanced', view_func=AdvancedView.as_view('advanced'))