Replace password reset with email OTP verification flow. Add auth_otp module, OTP templates, and email delivery. Expand styleguide CSS with full component library. Rework login, register, and admin views for cookie sessions. Remove legacy 2FA templates and password reset flow. Update SSH wrappers, forms, validators, and middleware.
58 lines
1.9 KiB
Python
58 lines
1.9 KiB
Python
import time
|
|
import logging
|
|
import functools
|
|
|
|
from pyramid.httpexceptions import HTTPFound
|
|
|
|
from rhodecode.lib import helpers as h
|
|
from rhodecode.model.meta import Session
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
SUDO_GRACE_PERIOD = 600 # 10 minutes
|
|
|
|
|
|
class SudoOTPRequired(object):
|
|
def __init__(self, func):
|
|
functools.update_wrapper(self, func)
|
|
self.func = func
|
|
|
|
def __get__(self, obj, cls):
|
|
return functools.partial(self.__call__, obj)
|
|
|
|
def __call__(self, method_self, *args, **kwargs):
|
|
session = method_self.request.session
|
|
verified_at = session.get("sudo_otp_verified_at", 0)
|
|
|
|
if (time.time() - verified_at) < SUDO_GRACE_PERIOD:
|
|
return self.func(method_self, *args, **kwargs)
|
|
|
|
# Need sudo verification — generate OTP and redirect
|
|
user = method_self._rhodecode_db_user
|
|
code = user.generate_otp("sudo", digits=8)
|
|
Session().commit()
|
|
|
|
import rhodecode
|
|
smtp_server = rhodecode.CONFIG.get('smtp_server')
|
|
log_code = code if not smtp_server else 'X' * len(code)
|
|
log.info('[OTP] code=%s email=%s purpose=sudo', log_code, user.email)
|
|
|
|
# Send OTP email
|
|
from rhodecode.lib.celerylib import tasks, run_task
|
|
from rhodecode.model.notification import EmailNotificationModel
|
|
|
|
email_kwargs = {
|
|
'otp_code': code,
|
|
'purpose': 'sudo',
|
|
}
|
|
(subject, email_body, email_body_plaintext) = EmailNotificationModel().render_email(
|
|
EmailNotificationModel.TYPE_OTP_CODE, **email_kwargs
|
|
)
|
|
run_task(tasks.send_email, [user.email], subject, email_body_plaintext, email_body)
|
|
|
|
# Store where to go after verification
|
|
session["sudo_next_url"] = method_self.request.url
|
|
if hasattr(session, 'save'):
|
|
session.save()
|
|
|
|
raise HTTPFound(method_self.request.route_path("sudo_otp_verify"))
|