unrhodecode/rhodecode/lib/auth_otp.py
russell@unturf.com 722c3bd369 Prototype: OTP auth, styleguide overhaul, login/session rework
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.
2026-03-04 16:44:40 -05:00

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"))