Login base
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
from couchpotato.api import api_docs, api_docs_missing, api
|
||||
from couchpotato.core.auth import requires_auth
|
||||
from couchpotato.core.event import fireEvent
|
||||
from couchpotato.core.helpers.variable import md5
|
||||
from couchpotato.core.helpers.variable import md5, tryInt
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.environment import Env
|
||||
from tornado import template
|
||||
from tornado.web import RequestHandler
|
||||
from tornado.web import RequestHandler, authenticated
|
||||
import os
|
||||
import time
|
||||
import traceback
|
||||
@@ -16,9 +15,23 @@ log = CPLog(__name__)
|
||||
views = {}
|
||||
template_loader = template.Loader(os.path.join(os.path.dirname(__file__), 'templates'))
|
||||
|
||||
|
||||
class BaseHandler(RequestHandler):
|
||||
|
||||
def get_current_user(self):
|
||||
username = Env.setting('username')
|
||||
password = Env.setting('password')
|
||||
|
||||
if username or password:
|
||||
print self.get_secure_cookie('user')
|
||||
return self.get_secure_cookie('user')
|
||||
else: # Login when no username or password are set
|
||||
return True
|
||||
|
||||
# Main web handler
|
||||
@requires_auth
|
||||
class WebHandler(RequestHandler):
|
||||
class WebHandler(BaseHandler):
|
||||
|
||||
@authenticated
|
||||
def get(self, route, *args, **kwargs):
|
||||
route = route.strip('/')
|
||||
if not views.get(route):
|
||||
@@ -28,7 +41,7 @@ class WebHandler(RequestHandler):
|
||||
try:
|
||||
self.write(views[route]())
|
||||
except:
|
||||
log.error('Failed doing web request "%s": %s', (route, traceback.format_exc()))
|
||||
log.error("Failed doing web request '%s': %s", (route, traceback.format_exc()))
|
||||
self.write({'success': False, 'error': 'Failed returning results'})
|
||||
|
||||
def addView(route, func, static = False):
|
||||
@@ -79,6 +92,38 @@ class KeyHandler(RequestHandler):
|
||||
self.write({'success': False, 'error': 'Failed returning results'})
|
||||
|
||||
|
||||
class LoginHandler(BaseHandler):
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
|
||||
if self.get_current_user():
|
||||
self.redirect('/')
|
||||
else:
|
||||
self.write(template_loader.load('login.html').generate())
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
|
||||
api = None
|
||||
|
||||
username = Env.setting('username')
|
||||
password = Env.setting('password')
|
||||
|
||||
if (self.get_argument('username') == username or not username) and (md5(self.get_argument('password')) == password or not password):
|
||||
api = Env.setting('api_key')
|
||||
|
||||
if api:
|
||||
remember_me = tryInt(self.get_argument('remember_me', default = 0))
|
||||
self.set_secure_cookie('user', api, expires_days = 30 if remember_me else 0)
|
||||
|
||||
self.redirect('/')
|
||||
|
||||
class LogoutHandler(BaseHandler):
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
self.clear_cookie('user')
|
||||
self.redirect('/login')
|
||||
|
||||
|
||||
def page_not_found(rh):
|
||||
index_url = Env.get('web_base')
|
||||
url = rh.request.uri[len(index_url):]
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
from couchpotato.core.helpers.variable import md5
|
||||
from couchpotato.environment import Env
|
||||
import base64
|
||||
|
||||
def check_auth(username, password):
|
||||
return username == Env.setting('username') and password == Env.setting('password')
|
||||
|
||||
def requires_auth(handler_class):
|
||||
|
||||
def wrap_execute(handler_execute):
|
||||
|
||||
def require_basic_auth(handler, kwargs):
|
||||
|
||||
if Env.setting('username') and Env.setting('password'):
|
||||
|
||||
auth_header = handler.request.headers.get('Authorization')
|
||||
auth_decoded = base64.decodestring(auth_header[6:]) if auth_header else None
|
||||
|
||||
username = ''
|
||||
password = ''
|
||||
|
||||
if auth_decoded:
|
||||
username, password = auth_decoded.split(':', 2)
|
||||
|
||||
if auth_header is None or not auth_header.startswith('Basic ') or (not check_auth(username.decode('latin'), md5(password.decode('latin')))):
|
||||
handler.set_status(401)
|
||||
handler.set_header('WWW-Authenticate', 'Basic realm="CouchPotato Login"')
|
||||
handler._transforms = []
|
||||
handler.finish()
|
||||
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _execute(self, transforms, *args, **kwargs):
|
||||
|
||||
if not require_basic_auth(self, kwargs):
|
||||
return False
|
||||
return handler_execute(self, transforms, *args, **kwargs)
|
||||
|
||||
return _execute
|
||||
|
||||
handler_class._execute = wrap_execute(handler_class._execute)
|
||||
|
||||
return handler_class
|
||||
@@ -1,6 +1,6 @@
|
||||
from argparse import ArgumentParser
|
||||
from cache import FileSystemCache
|
||||
from couchpotato import KeyHandler
|
||||
from couchpotato import KeyHandler, LoginHandler, LogoutHandler
|
||||
from couchpotato.api import NonBlockHandler, ApiHandler
|
||||
from couchpotato.core.event import fireEventAsync, fireEvent
|
||||
from couchpotato.core.helpers.encoding import toUnicode
|
||||
@@ -233,10 +233,11 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
|
||||
log_function = lambda x : None,
|
||||
debug = config['use_reloader'],
|
||||
gzip = True,
|
||||
cookie_secret = api_key,
|
||||
login_url = "/login",
|
||||
)
|
||||
Env.set('app', application)
|
||||
|
||||
|
||||
# Request handlers
|
||||
application.add_handlers(".*$", [
|
||||
(r'%snonblock/(.*)(/?)' % api_base, NonBlockHandler),
|
||||
@@ -245,6 +246,10 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
|
||||
(r'%s(.*)(/?)' % api_base, ApiHandler), # Main API handler
|
||||
(r'%sgetkey(/?)' % web_base, KeyHandler), # Get API key
|
||||
(r'%s' % api_base, RedirectHandler, {"url": web_base + 'docs/'}), # API docs
|
||||
|
||||
# Login handlers
|
||||
(r'%slogin(/?)' % web_base, LoginHandler),
|
||||
(r'%slogout(/?)' % web_base, LogoutHandler),
|
||||
|
||||
# Catch all webhandlers
|
||||
(r'%s(.*)(/?)' % web_base, WebHandler),
|
||||
|
||||
18
couchpotato/templates/login.html
Normal file
18
couchpotato/templates/login.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{% autoescape None %}
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<title>Login</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="" method="post">
|
||||
<div><input name="username" type="text" placeholder="Username" /></div>
|
||||
<div><input name="password" type="password" placeholder="Password" /></div>
|
||||
<div><label title="for 30 days"><input name="remember_me" type="checkbox" value="1" checked="checked" /> Remember me</label></div>
|
||||
<div><input name="submit" type="submit" value="Login" /></div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user