diff --git a/data/interfaces/default/js/tables/login_logs.js b/data/interfaces/default/js/tables/login_logs.js index 325ad973..d2cf605b 100644 --- a/data/interfaces/default/js/tables/login_logs.js +++ b/data/interfaces/default/js/tables/login_logs.js @@ -77,9 +77,24 @@ login_log_table_options = { { "targets": [6], "data": "browser", - "width": "20%", + "width": "18%", "className": "no-wrap" - } + }, + { + "targets": [7], + "data": "success", + "createdCell": function (td, cellData, rowData, row, col) { + if (cellData == 1) { + $(td).html(''); + } else { + $(td).html(''); + } + }, + "searchable": false, + "orderable": false, + "className": "no-wrap", + "width": "2%" + }, ], "drawCallback": function (settings) { // Jump to top of page diff --git a/data/interfaces/default/logs.html b/data/interfaces/default/logs.html index f82dfd59..b041b4a9 100644 --- a/data/interfaces/default/logs.html +++ b/data/interfaces/default/logs.html @@ -145,13 +145,14 @@ - - - - - - - + + + + + + + + diff --git a/plexpy/__init__.py b/plexpy/__init__.py index a72e3923..e04b3dd5 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -496,7 +496,8 @@ def dbcheck(): # user_login table :: This table keeps record of the PlexPy guest logins c_db.execute( 'CREATE TABLE IF NOT EXISTS user_login (id INTEGER PRIMARY KEY AUTOINCREMENT, ' - 'timestamp INTEGER, user_id INTEGER, user TEXT, user_group TEXT, ip_address TEXT, host TEXT, user_agent TEXT)' + 'timestamp INTEGER, user_id INTEGER, user TEXT, user_group TEXT, ' + 'ip_address TEXT, host TEXT, user_agent TEXT, success INTEGER DEFAULT 1)' ) # notifiers table :: This table keeps record of the notification agent settings @@ -1124,6 +1125,15 @@ def dbcheck(): 'DROP INDEX IF EXISTS idx_themoviedb_lookup_imdb_id' ) + # Upgrade user_login table from earlier versions + try: + c_db.execute('SELECT success FROM user_login') + except sqlite3.OperationalError: + logger.debug(u"Altering database. Updating database table user_login.") + c_db.execute( + 'ALTER TABLE user_login ADD COLUMN success INTEGER DEFAULT 1' + ) + # Add "Local" user to database as default unauthenticated user. result = c_db.execute('SELECT id FROM users WHERE username = "Local"') if not result.fetchone(): diff --git a/plexpy/users.py b/plexpy/users.py index 5a034f4a..4ba68f9f 100644 --- a/plexpy/users.py +++ b/plexpy/users.py @@ -678,7 +678,7 @@ class Users(object): return filters_list - def set_user_login(self, user_id=None, user=None, user_group=None, ip_address=None, host=None, user_agent=None): + def set_user_login(self, user_id=None, user=None, user_group=None, ip_address=None, host=None, user_agent=None, success=0): if user_id is None or str(user_id).isdigit(): monitor_db = database.MonitorDatabase() @@ -690,7 +690,8 @@ class Users(object): 'user_group': user_group, 'ip_address': ip_address, 'host': host, - 'user_agent': user_agent} + 'user_agent': user_agent, + 'success': success} try: monitor_db.upsert(table_name='user_login', key_dict=keys, value_dict=values) @@ -714,13 +715,14 @@ class Users(object): else: custom_where = [['user_login.user_id', user_id]] if user_id else [] - columns = ['user_login.user_id', + columns = ['user_login.timestamp', + 'user_login.user_id', 'user_login.user', 'user_login.user_group', 'user_login.ip_address', 'user_login.host', 'user_login.user_agent', - 'user_login.timestamp', + 'user_login.success', '(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" \ THEN users.username ELSE users.friendly_name END) AS friendly_name' ] @@ -744,14 +746,15 @@ class Users(object): for item in results: (os, browser) = httpagentparser.simple_detect(item['user_agent']) - row = {'user_id': item['user_id'], + row = {'timestamp': item['timestamp'], + 'user_id': item['user_id'], 'user_group': item['user_group'], 'ip_address': item['ip_address'], 'host': item['host'], 'user_agent': item['user_agent'], 'os': os, 'browser': browser, - 'timestamp': item['timestamp'], + 'success': item['success'], 'friendly_name': item['friendly_name'] or item['user'] } diff --git a/plexpy/webauth.py b/plexpy/webauth.py index 805bec7c..170141d8 100644 --- a/plexpy/webauth.py +++ b/plexpy/webauth.py @@ -190,7 +190,8 @@ class AuthController(object): user_group=user_group, ip_address=ip_address, host=host, - user_agent=user_agent) + user_agent=user_agent, + success=1) logger.debug(u"PlexPy WebAuth :: %s user '%s' logged into PlexPy." % (user_group.capitalize(), username)) @@ -198,6 +199,20 @@ class AuthController(object): """Called on logout""" logger.debug(u"PlexPy WebAuth :: %s User '%s' logged out of PlexPy." % (user_group.capitalize(), username)) + def on_login_failed(self, username): + """Called on failed login""" + + # Save login attempt to the database + ip_address = cherrypy.request.headers.get('X-Forwarded-For', cherrypy.request.headers.get('Remote-Addr')) + host = cherrypy.request.headers.get('Origin') + user_agent = cherrypy.request.headers.get('User-Agent') + + Users().set_user_login(user=username, + ip_address=ip_address, + host=host, + user_agent=user_agent, + success=0) + def get_loginform(self, username="", msg=""): from plexpy.webserve import serve_template return serve_template(templatename="login.html", title="Login", username=escape(username, True), msg=msg) @@ -240,9 +255,11 @@ class AuthController(object): raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT) elif admin_login == '1': + self.on_login_failed(username) logger.debug(u"PlexPy WebAuth :: Invalid admin login attempt from '%s'." % username) raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT) else: + self.on_login_failed(username) logger.debug(u"PlexPy WebAuth :: Invalid login attempt from '%s'." % username) return self.get_loginform(username, u"Incorrect username/email or password.")
TimestampUserUser GroupIP AddressHostOperating SystemBrowserTimestampUserUser GroupIP AddressHostOperating SystemBrowser