Coverage for webapp / decorators.py: 91%

32 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2025-12-29 22:06 +0000

1# Core packages 

2import functools 

3import logging 

4from datetime import datetime, timezone 

5 

6# Third party packages 

7import flask 

8 

9from canonicalwebteam.store_api.publishergw import PublisherGW 

10 

11from webapp import authentication 

12from webapp.helpers import api_publisher_session 

13 

14publisher_gateway = PublisherGW(api_publisher_session) 

15logger = logging.getLogger(__name__) 

16 

17 

18def login_required(func): 

19 """ 

20 Decorator that checks if a user is logged in, and redirects 

21 to login page if not. 

22 """ 

23 

24 @functools.wraps(func) 

25 def is_user_logged_in(*args, **kwargs): 

26 date = datetime.now(timezone.utc) 

27 date_str = date.strftime("%Y-%m-%dT%H:%M:%S") 

28 

29 if not authentication.is_authenticated(flask.session): 

30 authentication.empty_session(flask.session) 

31 

32 logger.warning( 

33 "User login failed", 

34 extra={ 

35 "datetime": date_str, 

36 "appid": "snapcraft-io", 

37 "event": "authn_login_fail", 

38 }, 

39 ) 

40 

41 return flask.redirect(f"/login?next={flask.request.path}") 

42 

43 publisher = flask.session.get("publisher") 

44 user = publisher["email"] 

45 

46 logger.info( 

47 f"User {user} login successfully", 

48 extra={ 

49 "datetime": date_str, 

50 "appid": "snapcraft-io", 

51 "event": f"authn_login_successafterfail:{user}", 

52 }, 

53 ) 

54 

55 return func(*args, **kwargs) 

56 

57 return is_user_logged_in 

58 

59 

60def exchange_required(func): 

61 @functools.wraps(func) 

62 def is_exchanged(*args, **kwargs): 

63 if "exchanged_developer_token" not in flask.session: 

64 result = publisher_gateway.exchange_dashboard_macaroons( 

65 flask.session 

66 ) 

67 flask.session["developer_token"] = result 

68 flask.session["exchanged_developer_token"] = True 

69 return func(*args, **kwargs) 

70 

71 return is_exchanged