mirror of
https://github.com/janeczku/calibre-web
synced 2025-01-11 18:00:30 +00:00
Update login routine (remember me working)
This commit is contained in:
parent
c09e1ed203
commit
1d3a768dfe
@ -19,12 +19,12 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
import ast
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
from .cw_login import LoginManager
|
||||||
|
from flask import session
|
||||||
|
|
||||||
from .cw_login import LoginManager, confirm_login
|
|
||||||
from flask import session, current_app
|
|
||||||
from .cw_login.utils import decode_cookie
|
|
||||||
from .cw_login.signals import user_loaded_from_cookie
|
|
||||||
|
|
||||||
|
|
||||||
class MyLoginManager(LoginManager):
|
class MyLoginManager(LoginManager):
|
||||||
@ -36,19 +36,5 @@ class MyLoginManager(LoginManager):
|
|||||||
return super(). _session_protection_failed()
|
return super(). _session_protection_failed()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _load_user_from_remember_cookie(self, cookie):
|
|
||||||
user_id = decode_cookie(cookie)
|
|
||||||
if user_id is not None:
|
|
||||||
session["_user_id"] = user_id
|
|
||||||
session["_fresh"] = False
|
|
||||||
user = None
|
|
||||||
if self._user_callback:
|
|
||||||
user = self._user_callback(user_id, None, None)
|
|
||||||
if user is not None:
|
|
||||||
app = current_app._get_current_object()
|
|
||||||
user_loaded_from_cookie.send(app, user=user)
|
|
||||||
# if session was restored from remember me cookie make login valid
|
|
||||||
confirm_login()
|
|
||||||
return user
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
import hashlib
|
||||||
|
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
@ -9,6 +10,8 @@ from flask import has_app_context
|
|||||||
from flask import redirect
|
from flask import redirect
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask import session
|
from flask import session
|
||||||
|
from itsdangerous import URLSafeSerializer
|
||||||
|
from flask.json.tag import TaggedJSONSerializer
|
||||||
|
|
||||||
from .config import AUTH_HEADER_NAME
|
from .config import AUTH_HEADER_NAME
|
||||||
from .config import COOKIE_DURATION
|
from .config import COOKIE_DURATION
|
||||||
@ -32,8 +35,7 @@ from .signals import user_needs_refresh
|
|||||||
from .signals import user_unauthorized
|
from .signals import user_unauthorized
|
||||||
from .utils import _create_identifier
|
from .utils import _create_identifier
|
||||||
from .utils import _user_context_processor
|
from .utils import _user_context_processor
|
||||||
from .utils import decode_cookie
|
from .utils import confirm_login
|
||||||
from .utils import encode_cookie
|
|
||||||
from .utils import expand_login_view
|
from .utils import expand_login_view
|
||||||
from .utils import login_url as make_login_url
|
from .utils import login_url as make_login_url
|
||||||
from .utils import make_next_param
|
from .utils import make_next_param
|
||||||
@ -323,7 +325,7 @@ class LoginManager:
|
|||||||
if self._user_callback is None and self._request_callback is None:
|
if self._user_callback is None and self._request_callback is None:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"Missing user_loader or request_loader. Refer to "
|
"Missing user_loader or request_loader. Refer to "
|
||||||
"http://flask-login.readthedocs.io/#how-it-works "
|
"https://flask-login.readthedocs.io/#how-it-works "
|
||||||
"for more info."
|
"for more info."
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -361,7 +363,8 @@ class LoginManager:
|
|||||||
elif header_name in request.headers:
|
elif header_name in request.headers:
|
||||||
header = request.headers[header_name]
|
header = request.headers[header_name]
|
||||||
user = self._load_user_from_header(header)
|
user = self._load_user_from_header(header)
|
||||||
|
if not user:
|
||||||
|
self._update_request_context_with_user()
|
||||||
return self._update_request_context_with_user(user)
|
return self._update_request_context_with_user(user)
|
||||||
|
|
||||||
def _session_protection_failed(self):
|
def _session_protection_failed(self):
|
||||||
@ -393,16 +396,32 @@ class LoginManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _load_user_from_remember_cookie(self, cookie):
|
def _load_user_from_remember_cookie(self, cookie):
|
||||||
user_id = decode_cookie(cookie)
|
signer_kwargs = dict(
|
||||||
if user_id is not None:
|
key_derivation="hmac", digest_method=staticmethod(hashlib.sha1)
|
||||||
session["_user_id"] = user_id
|
)
|
||||||
|
try:
|
||||||
|
remember_dict = URLSafeSerializer(
|
||||||
|
current_app.secret_key,
|
||||||
|
salt="remember",
|
||||||
|
serializer=TaggedJSONSerializer(),
|
||||||
|
signer_kwargs=signer_kwargs,
|
||||||
|
).loads(cookie)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if remember_dict['user'] is not None:
|
||||||
|
session["_user_id"] = remember_dict['user']
|
||||||
|
if "_random" not in session:
|
||||||
|
session["_random"] = remember_dict['random']
|
||||||
session["_fresh"] = False
|
session["_fresh"] = False
|
||||||
user = None
|
user = None
|
||||||
if self._user_callback:
|
if self._user_callback:
|
||||||
user = self._user_callback(user_id)
|
user = self._user_callback(remember_dict['user'], session["_random"], None)
|
||||||
if user is not None:
|
if user is not None:
|
||||||
app = current_app._get_current_object()
|
app = current_app._get_current_object()
|
||||||
user_loaded_from_cookie.send(app, user=user)
|
user_loaded_from_cookie.send(app, user=user)
|
||||||
|
# if session was restored from remember me cookie make login valid
|
||||||
|
confirm_login()
|
||||||
return user
|
return user
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -461,7 +480,17 @@ class LoginManager:
|
|||||||
duration = config.get("REMEMBER_COOKIE_DURATION", COOKIE_DURATION)
|
duration = config.get("REMEMBER_COOKIE_DURATION", COOKIE_DURATION)
|
||||||
|
|
||||||
# prepare data
|
# prepare data
|
||||||
data = encode_cookie(str(session["_user_id"]))
|
max_age = int(current_app.permanent_session_lifetime.total_seconds())
|
||||||
|
signer_kwargs = dict(
|
||||||
|
key_derivation="hmac", digest_method=staticmethod(hashlib.sha1)
|
||||||
|
)
|
||||||
|
# save
|
||||||
|
data = URLSafeSerializer(
|
||||||
|
current_app.secret_key,
|
||||||
|
salt="remember",
|
||||||
|
serializer=TaggedJSONSerializer(),
|
||||||
|
signer_kwargs=signer_kwargs,
|
||||||
|
).dumps({"user":session["_user_id"], "random":session["_random"]})
|
||||||
|
|
||||||
if isinstance(duration, int):
|
if isinstance(duration, int):
|
||||||
duration = timedelta(seconds=duration)
|
duration = timedelta(seconds=duration)
|
||||||
|
14
cps/ub.py
14
cps/ub.py
@ -74,10 +74,9 @@ def store_user_session():
|
|||||||
_user = flask_session.get('_user_id', "")
|
_user = flask_session.get('_user_id', "")
|
||||||
_id = flask_session.get('_id', "")
|
_id = flask_session.get('_id', "")
|
||||||
_random = flask_session.get('_random', "")
|
_random = flask_session.get('_random', "")
|
||||||
|
|
||||||
if flask_session.get('_user_id', ""):
|
if flask_session.get('_user_id', ""):
|
||||||
try:
|
try:
|
||||||
if not check_user_session(_user, _id):
|
if not check_user_session(_user, _id, _random):
|
||||||
expiry = int((datetime.datetime.now() + datetime.timedelta(days=31)).timestamp())
|
expiry = int((datetime.datetime.now() + datetime.timedelta(days=31)).timestamp())
|
||||||
user_session = User_Sessions(_user, _id, _random, expiry)
|
user_session = User_Sessions(_user, _id, _random, expiry)
|
||||||
session.add(user_session)
|
session.add(user_session)
|
||||||
@ -103,10 +102,12 @@ def delete_user_session(user_id, session_key):
|
|||||||
log.exception(ex)
|
log.exception(ex)
|
||||||
|
|
||||||
|
|
||||||
def check_user_session(user_id, session_key):
|
def check_user_session(user_id, session_key, random):
|
||||||
try:
|
try:
|
||||||
found = session.query(User_Sessions).filter(User_Sessions.user_id==user_id,
|
found = session.query(User_Sessions).filter(User_Sessions.user_id==user_id,
|
||||||
User_Sessions.session_key==session_key).one_or_none()
|
User_Sessions.session_key==session_key,
|
||||||
|
User_Sessions.random == random,
|
||||||
|
).one_or_none()
|
||||||
if found is not None:
|
if found is not None:
|
||||||
new_expiry = int((datetime.datetime.now() + datetime.timedelta(days=31)).timestamp())
|
new_expiry = int((datetime.datetime.now() + datetime.timedelta(days=31)).timestamp())
|
||||||
if new_expiry - found.expiry > 86400:
|
if new_expiry - found.expiry > 86400:
|
||||||
@ -614,10 +615,13 @@ def migrate_Database(_session):
|
|||||||
def clean_database(_session):
|
def clean_database(_session):
|
||||||
# Remove expired remote login tokens
|
# Remove expired remote login tokens
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
|
try:
|
||||||
_session.query(RemoteAuthToken).filter(now > RemoteAuthToken.expiration).\
|
_session.query(RemoteAuthToken).filter(now > RemoteAuthToken.expiration).\
|
||||||
filter(RemoteAuthToken.token_type != 1).delete()
|
filter(RemoteAuthToken.token_type != 1).delete()
|
||||||
_session.commit()
|
_session.commit()
|
||||||
|
except exc.OperationalError: # Database is not writeable
|
||||||
|
print('Settings database is not writeable. Exiting...')
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
# Save downloaded books per user in calibre-web's own database
|
# Save downloaded books per user in calibre-web's own database
|
||||||
|
@ -40,7 +40,6 @@ def verify_password(username, password):
|
|||||||
if user.name.lower() == "guest":
|
if user.name.lower() == "guest":
|
||||||
if config.config_anonbrowse == 1:
|
if config.config_anonbrowse == 1:
|
||||||
return user
|
return user
|
||||||
limiter.check()
|
|
||||||
if config.config_login_type == constants.LOGIN_LDAP and services.ldap:
|
if config.config_login_type == constants.LOGIN_LDAP and services.ldap:
|
||||||
login_result, error = services.ldap.bind_user(user.name, password)
|
login_result, error = services.ldap.bind_user(user.name, password)
|
||||||
if login_result:
|
if login_result:
|
||||||
@ -48,7 +47,9 @@ def verify_password(username, password):
|
|||||||
return user
|
return user
|
||||||
if error is not None:
|
if error is not None:
|
||||||
log.error(error)
|
log.error(error)
|
||||||
elif check_password_hash(str(user.password), password):
|
else:
|
||||||
|
limiter.check()
|
||||||
|
if check_password_hash(str(user.password), password):
|
||||||
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
|
[limiter.limiter.storage.clear(k.key) for k in limiter.current_limits]
|
||||||
return user
|
return user
|
||||||
ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
|
ip_address = request.headers.get('X-Forwarded-For', request.remote_addr)
|
||||||
@ -127,10 +128,14 @@ def load_user_from_reverse_proxy_header(req):
|
|||||||
@lm.user_loader
|
@lm.user_loader
|
||||||
def load_user(user_id, random, session_key):
|
def load_user(user_id, random, session_key):
|
||||||
user = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first()
|
user = ub.session.query(ub.User).filter(ub.User.id == int(user_id)).first()
|
||||||
if random and session_key:
|
if session_key:
|
||||||
entry = ub.session.query(ub.User_Sessions).filter(ub.User_Sessions.random == random,
|
entry = ub.session.query(ub.User_Sessions).filter(ub.User_Sessions.random == random,
|
||||||
ub.User_Sessions.session_key == session_key).first()
|
ub.User_Sessions.session_key == session_key).first()
|
||||||
if not entry or entry.user_id != user.id:
|
if not entry or entry.user_id != user.id:
|
||||||
return None
|
return None
|
||||||
|
elif random:
|
||||||
|
entry = ub.session.query(ub.User_Sessions).filter(ub.User_Sessions.random == random).first()
|
||||||
|
if not entry or entry.user_id != user.id:
|
||||||
|
return None
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user