Coverage for app / helpers / globals.py: 92%

37 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2025-12-06 04:49 +0000

1""" 

2This module is used to register global error handlers, context processors, and variables  

3for a Flask application. It ensures that custom error handling, utility functions, and  

4global variables (like `current_user`) are available to all templates and views. 

5""" 

6import time 

7 

8from flask import jsonify, session, request 

9from flask.sessions import NullSession 

10from flask_login import current_user 

11 

12THIRTY_MINUTES_IN_SECONDS = 1800 

13 

14 

15def register_globals(app): 

16 """ 

17 Register global error handlers, context processors, and variables for a Flask app. 

18 

19 This function sets up custom error handlers, Jinja2 context processors, and global  

20 variables to be made available throughout the lifecycle of a Flask request. 

21 """ 

22 

23 # Define the 403 error handler 

24 @app.errorhandler(403) 

25 def access_forbidden(e): 

26 """ 

27 Handles 403 Forbidden errors by returning a JSON response with an error message. 

28  

29 :param e: The exception that triggered the error 

30 :return: A JSON response object and a 403 HTTP status code 

31 """ 

32 return jsonify({'error': f'You do not have permission to access this resource {e}'}), 403 

33 

34 # Register the global Jinja2 context processor 

35 @app.context_processor 

36 def utility_processor(): 

37 """ 

38 Provides utility functions to the Jinja2 template context. 

39 

40 Returns a dictionary of helper functions that can be accessed directly within templates. 

41 """ 

42 from app.helpers.utilities import parse_url # pylint: disable=import-outside-toplevel 

43 return {"parse_url": parse_url} 

44 

45 @app.before_request 

46 def add_global_vars(): 

47 """ 

48 Adds global variables to the Jinja2 template environment before processing a request. 

49 

50 Makes information like the `current_user` available globally to all templates and macros. 

51 """ 

52 # Access the global Jinja environment, including in macros 

53 app.jinja_env.globals.update(current_user=current_user) 

54 

55 @app.before_request 

56 def before_request(): 

57 """ 

58 Implement sliding sessions 

59 """ 

60 if session and not isinstance(session, NullSession): 

61 session.permanent = True # Use a permanent session with the configured timeout 

62 session.modified = True # Update session timestamp on each request 

63 

64 @app.before_request 

65 def check_session_timeout(): 

66 """ 

67 Implement activity timeout 

68 """ 

69 if not session or isinstance(session, NullSession): 

70 return 

71 

72 current_time = time.time() 

73 if 'last_activity' in session: 

74 # If inactive for more than 30 minutes, clear the session 

75 if current_time - session['last_activity'] > THIRTY_MINUTES_IN_SECONDS: 75 ↛ 76line 75 didn't jump to line 76 because the condition on line 75 was never true

76 session.clear() 

77 session['last_activity'] = current_time 

78 

79 @app.before_request 

80 def check_ip_binding(): 

81 """ 

82 Bind session to an IP address 

83 :return: 

84 """ 

85 if not session or isinstance(session, NullSession): 

86 return 

87 

88 if 'user_ip' in session and session['user_ip'] != request.remote_addr: 88 ↛ 90line 88 didn't jump to line 90 because the condition on line 88 was never true

89 # IP address has changed, potential session hijacking 

90 session.clear() 

91 session['user_ip'] = request.remote_addr