mirror of
				https://github.com/avatao-content/test-tutorial-framework
				synced 2025-11-04 16:02:54 +00:00 
			
		
		
		
	Strip old sqli example app and replace it with a simple login service
This commit is contained in:
		@@ -1,27 +0,0 @@
 | 
			
		||||
import sqlite3
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_db():
 | 
			
		||||
    return sqlite3.connect('users.db')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def authorize_login(email, password):
 | 
			
		||||
    """
 | 
			
		||||
    This method checks if a user is authorized and has admin privileges.
 | 
			
		||||
    :param email: The email address of the user.
 | 
			
		||||
    :param password: The password of the user.
 | 
			
		||||
    :return: A tuple, the first element is the email address if the user exists,
 | 
			
		||||
    and None if they don't; the second element is a boolean, which is True if
 | 
			
		||||
    the user has admin privileges.
 | 
			
		||||
    """
 | 
			
		||||
    conn = get_db()
 | 
			
		||||
    sql_statement = '''SELECT email, is_admin FROM users
 | 
			
		||||
                       WHERE email="{}" AND password="{}"'''
 | 
			
		||||
    # The problem with this approach is that it substitutes any value received
 | 
			
		||||
    # from the user, even if it is a valid SQL statement!
 | 
			
		||||
    result = conn.execute(sql_statement.format(email, password)).fetchone()
 | 
			
		||||
    if result is None:
 | 
			
		||||
        return None, False
 | 
			
		||||
    else:
 | 
			
		||||
        email, is_admin = result
 | 
			
		||||
        return email, is_admin == 1
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
import json, sys
 | 
			
		||||
from tornado.ioloop import IOLoop
 | 
			
		||||
from tornado.web import RequestHandler, Application
 | 
			
		||||
 | 
			
		||||
from tfw.config import TFWENV
 | 
			
		||||
 | 
			
		||||
sys.path.append(TFWENV.IDE_WD)
 | 
			
		||||
from login_component import authorize_login
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LoginHandler(RequestHandler):
 | 
			
		||||
    def post(self, *args, **kwargs):
 | 
			
		||||
        request = json.loads(self.request.body)
 | 
			
		||||
        email, is_admin = authorize_login(
 | 
			
		||||
            request['email'],
 | 
			
		||||
            request['password']
 | 
			
		||||
        )
 | 
			
		||||
        self.write({
 | 
			
		||||
            'email': email,
 | 
			
		||||
            'is_admin': is_admin
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    application = Application([(r'/login', LoginHandler)])
 | 
			
		||||
    application.listen(TFWENV.LOGIN_APP_PORT)
 | 
			
		||||
    IOLoop.instance().start()
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								solvable/src/webservice/frontend-deps.tar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								solvable/src/webservice/frontend-deps.tar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										120
									
								
								solvable/src/webservice/server.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								solvable/src/webservice/server.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,120 @@
 | 
			
		||||
from os import urandom, getenv
 | 
			
		||||
from os.path import exists, join, dirname, realpath
 | 
			
		||||
from hashlib import sha512
 | 
			
		||||
 | 
			
		||||
import sqlite3
 | 
			
		||||
from flask import Flask, render_template, request, g, session, url_for
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def setup_db(filename):
 | 
			
		||||
    connection = sqlite3.connect(filename)
 | 
			
		||||
    cur = connection.cursor()
 | 
			
		||||
    cur.execute('''CREATE TABLE users
 | 
			
		||||
                   (
 | 
			
		||||
                      id INTEGER PRIMARY KEY,
 | 
			
		||||
                      username TEXT NOT NULL,
 | 
			
		||||
                      pwhash TEXT NOT NULL
 | 
			
		||||
                   )
 | 
			
		||||
                ''')
 | 
			
		||||
    connection.commit()
 | 
			
		||||
    connection.close()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BASEURL = getenv('BASEURL', '')
 | 
			
		||||
DBFILE = join(dirname(realpath(__file__)), '.db.db')
 | 
			
		||||
SALT = 'justsomerandombytes'.encode()
 | 
			
		||||
if not exists(DBFILE):
 | 
			
		||||
    setup_db(DBFILE)
 | 
			
		||||
app = Flask(__name__)
 | 
			
		||||
app.secret_key = urandom(32)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_url(endpoint):
 | 
			
		||||
    return f'{BASEURL}{url_for(endpoint)}'
 | 
			
		||||
app.jinja_env.globals.update(get_url=get_url)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.before_request
 | 
			
		||||
def init_database():
 | 
			
		||||
    g.db = sqlite3.connect(DBFILE)
 | 
			
		||||
    g.db.row_factory = sqlite3.Row
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.teardown_request
 | 
			
		||||
def close_database(exception):
 | 
			
		||||
    db = getattr(g, 'db', None)
 | 
			
		||||
    if db is not None:
 | 
			
		||||
        db.close()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/', methods=['GET', 'POST'])
 | 
			
		||||
def index():
 | 
			
		||||
    if request.method == 'POST':
 | 
			
		||||
        cur = g.db.cursor()
 | 
			
		||||
        cur.execute('SELECT * FROM users WHERE username=? AND pwhash=?', 
 | 
			
		||||
                    [request.form['username'], sha512(request.form['password'].encode()+SALT).hexdigest()])
 | 
			
		||||
        query = cur.fetchone()
 | 
			
		||||
        if not query:
 | 
			
		||||
            return render_template('login.html', alert='Invalid credentials!')
 | 
			
		||||
        else:
 | 
			
		||||
            session['logged_in'] = True
 | 
			
		||||
            session['username'] = request.form['username']
 | 
			
		||||
            return render_template('internal.html')
 | 
			
		||||
    
 | 
			
		||||
    if session.get('logged_in'):
 | 
			
		||||
        return render_template('internal.html')
 | 
			
		||||
    return render_template('login.html')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/register', methods=['GET', 'POST'])
 | 
			
		||||
def register():
 | 
			
		||||
    if request.method == 'POST':
 | 
			
		||||
        cur = g.db.cursor()
 | 
			
		||||
 | 
			
		||||
        if not request.form['username'] or not request.form['password'] or not request.form['passwordconfirm']:
 | 
			
		||||
            return render_template('register.html', alert='You need to fill everything.')
 | 
			
		||||
        if request.form['password'] != request.form['passwordconfirm']:
 | 
			
		||||
            return render_template('register.html', alert='Passwords do not match! Please try again.')
 | 
			
		||||
 | 
			
		||||
        cur.execute('SELECT * FROM users WHERE username=?', [request.form['username']])
 | 
			
		||||
        if cur.fetchone() is not None:
 | 
			
		||||
            return render_template('register.html', alert='Username already in use.')
 | 
			
		||||
 | 
			
		||||
        cur.execute('INSERT INTO users(username, pwhash) VALUES(?,?)', 
 | 
			
		||||
                    [request.form['username'], 
 | 
			
		||||
                     sha512(request.form['password'].encode()+SALT).hexdigest()])
 | 
			
		||||
        g.db.commit()
 | 
			
		||||
 | 
			
		||||
        return render_template('login.html', success='Account "{}" successfully registered. You can log in now!'.format(request.form['username']))
 | 
			
		||||
 | 
			
		||||
    return render_template('register.html')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/logout')
 | 
			
		||||
def logout():
 | 
			
		||||
    try:
 | 
			
		||||
        session.pop('logged_in')
 | 
			
		||||
        session.pop('username')
 | 
			
		||||
    except KeyError:
 | 
			
		||||
        pass
 | 
			
		||||
    return render_template('login.html')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.errorhandler(401)
 | 
			
		||||
@app.errorhandler(404)
 | 
			
		||||
@app.route('/error')
 | 
			
		||||
def error(error):
 | 
			
		||||
    return render_template('error.html', error=error), error.code
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 500 needs a separate handler, as Flask would print
 | 
			
		||||
# the actual piece of code that caused the exception
 | 
			
		||||
# for some bizarre reason
 | 
			
		||||
@app.errorhandler(500)
 | 
			
		||||
@app.route('/error')
 | 
			
		||||
def servererror(error):
 | 
			
		||||
    return render_template('error.html', error='500: Internal server error'), 500
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    app.run(host='127.0.0.1', debug=False, port=6666)
 | 
			
		||||
							
								
								
									
										44
									
								
								solvable/src/webservice/templates/base.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								solvable/src/webservice/templates/base.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta charset="utf-8"> 
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
        <link rel="stylesheet" href="static/bootstrap-3.3.7/css/bootstrap.min.css">
 | 
			
		||||
        <script src="static/jquery-3.2.1.min.js"></script>
 | 
			
		||||
        <script src="static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
 | 
			
		||||
        <script>
 | 
			
		||||
        {% block script %}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
        </script>
 | 
			
		||||
        <style>
 | 
			
		||||
        .jumbotron h1 a
 | 
			
		||||
        {
 | 
			
		||||
            color: inherit;
 | 
			
		||||
            text-decoration: none;
 | 
			
		||||
        }
 | 
			
		||||
        {% block style %}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
        </style>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <div class="jumbotron text-center">
 | 
			
		||||
            <h1><a href="{{get_url('index')}}">SomeSite</a></h1>
 | 
			
		||||
            <p>We provide stuff!</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="container-fluid">
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-md-6 col-md-offset-3 col-sm-12">
 | 
			
		||||
                    {% if alert or success %}
 | 
			
		||||
                    <div class="alert alert-{{'success' if success else 'danger'}} alert-dismissable fade in center-block">
 | 
			
		||||
                        <a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
 | 
			
		||||
                        <div class="message">{{alert}}{{success}}</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    {% block content %}
 | 
			
		||||
                    {% endblock %}
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								solvable/src/webservice/templates/error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								solvable/src/webservice/templates/error.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<h3>Oops, something went wrong! :(</h3>
 | 
			
		||||
<h2>{{error}}</h2>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										9
									
								
								solvable/src/webservice/templates/internal.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								solvable/src/webservice/templates/internal.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<h2>Welcome, {{session.username}}</h2>
 | 
			
		||||
<p>You have successfully logged in</p>
 | 
			
		||||
<a href="{{get_url('logout')}}" class="btn btn-default" >
 | 
			
		||||
    <span class="glyphicon glyphicon-log-out"></span> Logout
 | 
			
		||||
</a>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										27
									
								
								solvable/src/webservice/templates/login.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								solvable/src/webservice/templates/login.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
{% block style %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
{% block script %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<h2>Login</h2>
 | 
			
		||||
<form method="post" action="{{get_url('index')}}">
 | 
			
		||||
    <div class="input-group">
 | 
			
		||||
        <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
 | 
			
		||||
        <input type="text" name="username" class="form-control" placeholder="Username" autofocus required />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="input-group">
 | 
			
		||||
        <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
 | 
			
		||||
        <input type="password" name="password" class="form-control" placeholder="Password" required />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="well">Not a member yet? <a href="{{get_url('register')}}">Register here</a>.</div>
 | 
			
		||||
    <input type="submit" class="btn btn-success" value="Login!" />
 | 
			
		||||
</form>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										20
									
								
								solvable/src/webservice/templates/register.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								solvable/src/webservice/templates/register.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
{% extends "base.html" %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
<h2>You can register using this form.</h2>
 | 
			
		||||
<form method="post" action="{{get_url('register')}}">
 | 
			
		||||
    <div class="input-group">
 | 
			
		||||
        <span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
 | 
			
		||||
        <input type="text" name="username" class="form-control" placeholder="Username" autofocus required />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="input-group">
 | 
			
		||||
        <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
 | 
			
		||||
        <input type="password" name="password" class="form-control" placeholder="Password" required />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="input-group">
 | 
			
		||||
        <span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
 | 
			
		||||
        <input type="password" name="passwordconfirm" class="form-control" placeholder="Confirm password" required />
 | 
			
		||||
    </div>
 | 
			
		||||
    <input type="submit" class="btn btn-success" value="Register!" />
 | 
			
		||||
</form>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
		Reference in New Issue
	
	Block a user