Make it possible to list and invalidate active sessions
This commit is contained in:
		| @@ -17,7 +17,7 @@ | ||||
| """Main module for the Calendar.social app | ||||
| """ | ||||
|  | ||||
| from flask import Blueprint, abort, current_app, redirect, render_template, url_for | ||||
| from flask import Blueprint, abort, current_app, flash, redirect, render_template, session, url_for | ||||
| from flask_security import current_user, login_required | ||||
|  | ||||
| from sqlalchemy.orm.exc import NoResultFound | ||||
| @@ -197,3 +197,38 @@ class AccountBlueprint(Blueprint, RoutedMixin): | ||||
|             db.session.commit() | ||||
|  | ||||
|         return redirect(url_for('account.follow_requests')) | ||||
|  | ||||
|     @staticmethod | ||||
|     @RoutedMixin.route('/sessions') | ||||
|     @login_required | ||||
|     def active_sessions(): | ||||
|         """View the list of active sessions | ||||
|         """ | ||||
|  | ||||
|         sessions = [] | ||||
|  | ||||
|         for sid in current_user.active_sessions: | ||||
|             session = current_app.session_interface.load_session(sid) | ||||
|             sessions.append(session) | ||||
|  | ||||
|         return render_template('account/active-sessions.html', sessions=sessions) | ||||
|  | ||||
|     @staticmethod | ||||
|     @RoutedMixin.route('/sessions/invalidate/<string:sid>') | ||||
|     @login_required | ||||
|     def invalidate_session(sid): | ||||
|         """View to invalidate a session | ||||
|         """ | ||||
|  | ||||
|         sess = current_app.session_interface.load_session(sid) | ||||
|  | ||||
|         if not sess or sess.user != current_user: | ||||
|             abort(404) | ||||
|  | ||||
|         if sess.sid == session.sid: | ||||
|             flash(_('Can’t invalidate your current session')) | ||||
|         else: | ||||
|             current_app.session_interface.delete_session(sid) | ||||
|             current_user.active_sessions = [sess_id for sess_id in current_user.active_sessions if sess_id != sid] | ||||
|  | ||||
|         return redirect(url_for('account.active_sessions')) | ||||
|   | ||||
| @@ -27,6 +27,7 @@ from flask_sqlalchemy import SQLAlchemy | ||||
| from sqlalchemy.orm.exc import NoResultFound | ||||
| from sqlalchemy_utils.types.choice import ChoiceType | ||||
|  | ||||
| from .cache import cache | ||||
| from .utils import force_locale | ||||
|  | ||||
| db = SQLAlchemy() | ||||
| @@ -219,6 +220,21 @@ class User(db.Model, UserMixin): | ||||
|  | ||||
|         return current_app.timezone | ||||
|  | ||||
|     @property | ||||
|     def session_list_key(self): | ||||
|         """The cache key of this user’s session list | ||||
|         """ | ||||
|  | ||||
|         return f'open_sessions:{self.id}' | ||||
|  | ||||
|     @property | ||||
|     def active_sessions(self): | ||||
|         return cache.get(self.session_list_key) or [] | ||||
|  | ||||
|     @active_sessions.setter | ||||
|     def active_sessions(self, value): | ||||
|         cache.set(self.session_list_key, list(value)) | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return f'<User {self.id}({self.username})>' | ||||
|  | ||||
|   | ||||
							
								
								
									
										15
									
								
								calsocial/templates/account/active-sessions.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								calsocial/templates/account/active-sessions.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| {% extends 'account/settings-base.html' %} | ||||
|  | ||||
| {% block settings_content %} | ||||
| <h2>{% trans %}Active sessions{% endtrans %}</h2> | ||||
| <ul> | ||||
|     {% for sess in sessions %} | ||||
|     <li> | ||||
|         {{ sess['ip'] }} | ||||
|         {% if sess.sid != session.sid %} | ||||
|         <a href="{{ url_for('account.invalidate_session', sid=sess.sid) }}">{% trans %}Invalidate{% endtrans %}</a> | ||||
|         {% endif %} | ||||
|     </li> | ||||
|     {% endfor %} | ||||
| </ul> | ||||
| {% endblock settings_content %} | ||||
| @@ -6,6 +6,7 @@ | ||||
|         <div class="ui secondary pointing vertical menu"> | ||||
|             <a class="item{% if request.endpoint == 'account.edit_profile' %} active{% endif %}" href="{{ url_for('account.edit_profile') }}">{% trans %}Edit profile{% endtrans %}</a> | ||||
|             <a class="item{% if request.endpoint == 'account.settings' %} active{% endif %}" href="{{ url_for('account.settings') }}">{% trans %}Settings{% endtrans %}</a> | ||||
|             <a class="item{% if request.endpoint == 'account.active_sessions' %} active{% endif %}" href="{{ url_for('account.active_sessions') }}">{% trans %}Active sessions{% endtrans %}</a> | ||||
|         </div> | ||||
|     </div> | ||||
|     <div class="twelve wide stretched column"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user