diff --git a/apps/challenges/views.py b/apps/challenges/views.py index 11f6df62f2..6c3c6c8dcc 100644 --- a/apps/challenges/views.py +++ b/apps/challenges/views.py @@ -3131,10 +3131,33 @@ def invite_users_to_challenge(request, challenge_pk): response_data = {"error": "Users email can't be blank"} return Response(response_data, status=status.HTTP_400_BAD_REQUEST) + # Parse emails safely using json.loads instead of dangerous eval() try: - users_email = eval(users_email) - except Exception: - response_data = {"error": "Invalid format for users email"} + # If users_email is already a list (from JSON request body), use it directly + if isinstance(users_email, list): + parsed_emails = users_email + # Otherwise, parse the JSON string + elif isinstance(users_email, str): + parsed_emails = json.loads(users_email) + else: + response_data = {"error": "Invalid email format. Expected a list of email addresses."} + return Response(response_data, status=status.HTTP_400_BAD_REQUEST) + + # Validate that the result is a list + if not isinstance(parsed_emails, list): + response_data = {"error": "Invalid email format. Expected a list of email addresses."} + return Response(response_data, status=status.HTTP_400_BAD_REQUEST) + + # Validate that all items in the list are strings + if not all(isinstance(email, str) for email in parsed_emails): + response_data = {"error": "All email addresses must be strings."} + return Response(response_data, status=status.HTTP_400_BAD_REQUEST) + + users_email = parsed_emails + + except (json.JSONDecodeError, TypeError, ValueError) as e: + logger.error(f"Error parsing email list: {str(e)}") + response_data = {"error": "Invalid JSON format for users email"} return Response(response_data, status=status.HTTP_400_BAD_REQUEST) invalid_emails = [] diff --git a/bower.json b/bower.json index 0b9d0ea662..a96a44cc3e 100644 --- a/bower.json +++ b/bower.json @@ -35,7 +35,8 @@ "moment-picker": "0.10.2", "angular-moment-picker": "moment-picker#^0.10.2", "moment-timezone": "^0.5.25", - "trix": "1.3.1" + "trix": "1.3.1", + "ngMeta": "vinaygopinath/ngMeta" }, "resolutions": { "angular": "1.7.0" diff --git a/frontend/app.scripts.json b/frontend/app.scripts.json index cb8d7e03c1..423d2e9a5d 100644 --- a/frontend/app.scripts.json +++ b/frontend/app.scripts.json @@ -24,7 +24,8 @@ "angular-moment", "clipboard", "ngclipboard", - "moment-picker" + "moment-picker", + "ngMeta" ] }, "paths": { @@ -51,6 +52,7 @@ "angular-moment": "bower_components/angular-moment/angular-moment.js", "clipboard": "bower_components/clipboard/dist/clipboard.min.js", "ngclipboard": "bower_components/ngclipboard/dist/ngclipboard.min.js", - "moment-picker": "bower_components/angular-moment-picker/dist/angular-moment-picker.js" + "moment-picker": "bower_components/angular-moment-picker/dist/angular-moment-picker.js", + "ngMeta": "bower_components/ngMeta/dest/ngMeta.min.js" } } diff --git a/frontend/base.html b/frontend/base.html index cf77da6193..af9fa55ba4 100644 --- a/frontend/base.html +++ b/frontend/base.html @@ -2,20 +2,23 @@
-