Ensure you can only view/edit http functions created by the currently logged in user

This commit is contained in:
Peter Stockings
2023-12-20 22:57:39 +11:00
parent 30e16277df
commit 8d38c39604
6 changed files with 48 additions and 37 deletions

44
app.py
View File

@@ -7,7 +7,7 @@ from flask_htmx import HTMX
import requests
from db import DataBase
from services import create_http_function_view_model, create_http_functions_view_model
from flask_login import LoginManager, UserMixin, login_required, login_user
from flask_login import LoginManager, UserMixin, current_user, login_required, login_user
from werkzeug.security import check_password_hash, generate_password_hash
login_manager = LoginManager()
@@ -77,9 +77,10 @@ def map_isolator_response_to_flask_response(response):
def home():
return render_template("home.html", name='Try me', script=DEFAULT_SCRIPT, environment_info=DEFAULT_ENVIRONMENT)
@ app.route("/client/<function>", methods=["GET"])
def client(function):
http_function = db.get_http_function(function)
@ app.route("/client/<int:user_id>/<function>", methods=["GET"])
@login_required
def client(user_id, function):
http_function = db.get_http_function(user_id, function)
if not http_function:
return jsonify({'error': 'Function not found'}), 404
@@ -89,14 +90,16 @@ def client(function):
@ app.route("/dashboard", methods=["GET"])
@login_required
def dashboard():
http_functions = db.get_http_functions()
user_id = current_user.id
http_functions = db.get_http_functions_for_user(user_id)
http_functions = create_http_functions_view_model(http_functions)
return render_template("dashboard.html", http_functions=http_functions)
@ app.route("/dashboard/http_functions", methods=["GET"])
@login_required
def dashboard_http_functions():
http_functions = db.get_http_functions()
user_id = current_user.id
http_functions = db.get_http_functions_for_user(user_id)
http_functions = create_http_functions_view_model(http_functions)
return render_template("dashboard/http_functions.html", http_functions=http_functions)
@@ -109,13 +112,14 @@ def get_http_function_add_form():
@login_required
def create_http_function():
try:
user_id = current_user.id
name = request.json.get('name')
script_content = request.json.get('script_content')
environment_info = json.dumps(eval(request.json.get('environment_info')))
db.create_new_http_function(name, script_content, environment_info)
db.create_new_http_function(user_id, name, script_content, environment_info)
http_functions = db.get_http_functions()
http_functions = db.get_http_functions_for_user(user_id)
http_functions = create_http_functions_view_model(http_functions)
return render_template("dashboard/http_functions.html", http_functions=http_functions)
except Exception as e:
@@ -125,23 +129,25 @@ def create_http_function():
@ app.route("/dashboard/http_functions/edit_form", methods=["GET"])
@login_required
def get_http_function_edit_form():
user_id = current_user.id
name = request.args.get('name')
http_function = db.get_http_function(name)
http_function = db.get_http_function(user_id, name)
if not http_function:
return jsonify({'error': 'Function not found'}), 404
script = http_function['script_content']
environment_info = json.dumps(http_function['environment_info'], indent=2)
return render_template("dashboard/http_functions/edit.html", name=name, script=script, environment_info=environment_info)
return render_template("dashboard/http_functions/edit.html", user_id=user_id, name=name, script=script, environment_info=environment_info)
@ app.route("/dashboard/http_functions/edit", methods=["POST"])
@login_required
def edit_http_function():
try:
user_id = current_user.id
name = request.json.get('name')
script_content = request.json.get('script_content')
environment_info = json.dumps(eval(request.json.get('environment_info')))
db.edit_http_function(name, script_content, environment_info)
db.edit_http_function(user_id, name, script_content, environment_info)
return { "status": "success", "message": f'{name} updated' }
except Exception as e:
print(e)
@@ -154,7 +160,8 @@ def delete_http_function():
name = request.args.get('name')
db.delete_http_function(name)
http_functions = db.get_http_functions()
user_id = current_user.id
http_functions = db.get_http_functions_for_user(user_id)
http_functions = create_http_functions_view_model(http_functions)
return render_template("dashboard/http_functions.html", http_functions=http_functions)
except Exception as e:
@@ -163,14 +170,15 @@ def delete_http_function():
@ app.route("/dashboard/http_functions/logs", methods=["GET"])
@login_required
def get_http_function_logs():
user_id = current_user.id
name = request.args.get('name')
http_function = db.get_http_function(name)
http_function = db.get_http_function(user_id, name)
if not http_function:
return jsonify({'error': 'Function not found'}), 404
http_function_id = http_function['id']
http_function_invocations = db.get_http_function_invocations(http_function_id)
return render_template("dashboard/http_functions/logs.html", name=name, http_function_invocations=http_function_invocations)
return render_template("dashboard/http_functions/logs.html", user_id=user_id, name=name, http_function_invocations=http_function_invocations)
@ app.route("/dashboard/timer_functions", methods=["GET"])
@@ -210,10 +218,10 @@ def execute_code():
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/f/<function>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'])
def execute_http_function(function):
@app.route('/f/<int:user_id>/<function>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS', 'HEAD'])
def execute_http_function(user_id, function):
try:
http_function = db.get_http_function(function)
http_function = db.get_http_function(user_id, function)
if not http_function:
return jsonify({'error': 'Function not found'}), 404
@@ -247,7 +255,7 @@ def execute_http_function(function):
response = requests.post(API_URL, json={'code': code, 'request': request_data, 'environment': environment})
response_data = response.json()
db.update_http_function_environment_info_and_invoked_count(function, response_data['environment'])
db.update_http_function_environment_info_and_invoked_count(user_id, function, response_data['environment'])
db.add_http_function_invocation(http_function['id'], response_data['status'], request_data, response_data['result'], response_data['logs'])
# Map the Node.js response to Flask response

24
db.py
View File

@@ -47,31 +47,31 @@ class DataBase():
return (rv[0] if rv else None) if one else rv
def get_http_functions(self):
def get_http_functions_for_user(self, user_id):
http_functions = self.execute(
'SELECT id, NAME, script_content, invoked_count, environment_info FROM http_functions ORDER by id DESC', [])
'SELECT id, user_id, NAME, script_content, invoked_count, environment_info FROM http_functions WHERE user_id=%s ORDER by id DESC', [user_id])
return http_functions
def get_http_function(self, name):
def get_http_function(self, user_id, name):
http_function = self.execute(
'SELECT id, NAME, script_content, invoked_count, environment_info FROM http_functions WHERE NAME=%s', [name], one=True)
'SELECT id, user_id, NAME, script_content, invoked_count, environment_info FROM http_functions WHERE user_id=%s AND NAME=%s', [user_id, name], one=True)
return http_function
def create_new_http_function(self, name, script_content, environment_info):
def create_new_http_function(self, user_id, name, script_content, environment_info):
self.execute(
'INSERT INTO http_functions (NAME, script_content, environment_info) VALUES (%s, %s, %s)', [name, script_content, environment_info], commit=True)
'INSERT INTO http_functions (user_id, NAME, script_content, environment_info) VALUES (%s, %s, %s, %s)', [user_id, name, script_content, environment_info], commit=True)
def edit_http_function(self, name, script_content, environment_info):
def edit_http_function(self, user_id, name, script_content, environment_info):
self.execute(
'UPDATE http_functions SET script_content=%s, environment_info=%s WHERE NAME=%s', [script_content, environment_info, name], commit=True)
'UPDATE http_functions SET script_content=%s, environment_info=%s WHERE user_id=%s AND NAME=%s', [script_content, environment_info, user_id, name], commit=True)
def update_http_function_environment_info_and_invoked_count(self, name, environment_info):
def update_http_function_environment_info_and_invoked_count(self, user_id, name, environment_info):
self.execute(
'UPDATE http_functions SET environment_info=%s, invoked_count = invoked_count + 1 WHERE NAME=%s', [json.dumps(environment_info), name], commit=True)
'UPDATE http_functions SET environment_info=%s, invoked_count = invoked_count + 1 WHERE user_id=%s AND NAME=%s', [json.dumps(environment_info), user_id, name], commit=True)
def delete_http_function(self, name):
def delete_http_function(self, user_id, name):
self.execute(
'DELETE FROM http_functions WHERE NAME=%s', [name], commit=True)
'DELETE FROM http_functions WHERE user_id=%s AND NAME=%s', [user_id, name], commit=True)
def add_http_function_invocation(self, http_function_id, status, request_data, response_data, logs):
self.execute(

View File

@@ -1,6 +1,7 @@
def create_http_function_view_model(http_function):
function_view_model = {
"id": http_function['id'],
"user_id": http_function['user_id'],
"name": http_function['name'],
"script_content": http_function['script_content'],
"invoked_count": http_function['invoked_count'],

View File

@@ -30,8 +30,9 @@
</span>
</td>
<td class="p-4 align-middle [&amp;:has([role=checkbox])]:pr-0 hidden md:table-cell" data-id="67">
<a href="{{ url_for('execute_http_function', function=function.name) }}">{{
url_for('execute_http_function', function=function.name) }}</a>
<a
href="{{ url_for('execute_http_function', user_id=function.user_id, function=function.name) }}">{{
url_for('execute_http_function', user_id=function.user_id, function=function.name) }}</a>
<button
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground pl-1 text-gray-600 dark:text-gray-400"
data-id="24"><span class="sr-only" data-id="25">Add Link</span><svg
@@ -61,7 +62,8 @@
</button>
<button
class="inline-flex items-center justify-center text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-9 rounded-md px-3"
data-id="69" hx-get="{{ url_for('client', function=function.name) }}"
data-id="69"
hx-get="{{ url_for('client', user_id=function.user_id, function=function.name) }}"
hx-target="#container" hx-swap="innerHTML">
Try
</button>

View File

@@ -25,8 +25,8 @@
</button>
</div>
<div class="flex">
<a class="text-gray-300" href="{{ url_for('execute_http_function', function=name) }}">{{
url_for('execute_http_function', function=name) }}</a>
<a class="text-gray-300" href="{{ url_for('execute_http_function', user_id=user_id, function=name) }}">{{
url_for('execute_http_function', user_id=user_id, function=name) }}</a>
<button
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground px-2 text-gray-600 dark:text-gray-400"
data-id="24"><span class="sr-only" data-id="25">Add Link</span><svg xmlns="http://www.w3.org/2000/svg"

View File

@@ -24,8 +24,8 @@
</button>
</div>
<div class="flex">
<a class="text-gray-300" href="{{ url_for('execute_http_function', function=name) }}">{{
url_for('execute_http_function', function=name) }}</a>
<a class="text-gray-300" href="{{ url_for('execute_http_function', user_id=user_id, function=name) }}">{{
url_for('execute_http_function', user_id=user_id, function=name) }}</a>
<button
class="inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground px-2 text-gray-600 dark:text-gray-400"
data-id="24"><span class="sr-only" data-id="25">Add Link</span><svg xmlns="http://www.w3.org/2000/svg"