pgadmin4 中的 setup.py 存在问题(导入错误烧瓶安全性)

问题描述 投票:0回答:1

python setup.py
Traceback (most recent call last):
  File "C:\Users\Mynamefake\AppData\Local\Programs\pgAdmin 4\web\setup.py", line 220, in <module>
    app = create_app()
          ^^^^^^^^^^^^
  File "C:\Users\Mynamefake\AppData\Local\Programs\pgAdmin 4\web\pgadmin\__init__.py", line 534, in create_app
    authenticate.init_app(app)
  File "C:\Users\Mynamefake\AppData\Local\Programs\pgAdmin 4\web\pgadmin\authenticate\__init__.py", line 341, in init_app
    AuthSourceRegistry.load_modules(app)
  File "C:\Users\Mynamefake\AppData\Local\Programs\pgAdmin 4\web\pgadmin\authenticate\registry.py", line 39, in load_modules
    module.__dict__["init_app"](app)
  File "C:\Users\Mynamefake\AppData\Local\Programs\pgAdmin 4\web\pgadmin\authenticate\mfa\__init__.py", line 60, in init_app
    MultiFactorAuthRegistry.load_modules(app)
  File "C:\Users\Mynamefake\AppData\Local\Programs\pgAdmin 4\web\pgadmin\authenticate\mfa\registry.py", line 32, in load_modules
    from . import email as module
  File "C:\Users\Mynamefake\AppData\Local\Programs\pgAdmin 4\web\pgadmin\authenticate\mfa\email.py", line 15, in <module>
    from flask_security import send_mail
ImportError: cannot import name 'send_mail' from 'flask_security' (C:\Users\Mynamefake\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\flask_security\__init__.py)

这是 email.py 的代码

##############################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2023, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##############################################################################
"""Multi-factor Authentication implementation by sending OTP through email"""

from flask import url_for, session, Response, render_template, current_app, \
    flash
from flask_babel import gettext as _
from flask_login import current_user
from flask_security import send_mail

import config
from pgadmin.utils.csrf import pgCSRFProtect
from .registry import BaseMFAuth
from .utils import ValidationException, mfa_add, fetch_auth_option
from pgadmin.utils.constants import MessageType


def __generate_otp() -> str:
    """
    Generate a six-digits one-time-password (OTP) for the current user.

    Returns:
        str: A six-digits OTP for the current user
    """
    import time
    import codecs
    import secrets

    code = codecs.encode("{}{}{}".format(
        time.time(), current_user.username, secrets.choice(range(1000, 9999))
    ).encode(), "hex")

    res = 0
    idx = 0

    while idx < len(code):
        res += int((code[idx:idx + 6]).decode('utf-8'), base=16)
        res %= 1000000
        idx += 5

    return str(res).zfill(6)


def _send_code_to_email(_email: str = None) -> (bool, int, str):
    """
    Send the code to the email address, provided in the argument or to the
    email address of the current user, provided during the registration.

    Args:
        _email (str, optional): Email Address, where to send the OTP code.
                                Defaults to None.

    Returns:
        (bool, int, str): Returns a set as (failed?, HTTP Code, message string)
                          If 'failed?' is True, message contains the error
                          message for the user, else it contains the success
                          message for the user to consume.
    """

    if not current_user.is_authenticated:
        return False, 401, _("Not accessible")

    if _email is None:
        _email = getattr(current_user, 'email', None)

    if _email is None:
        return False, 401, _("No email address is available.")

    try:
        session["mfa_email_code"] = __generate_otp()
        subject = getattr(config, 'MFA_EMAIL_SUBJECT', None)

        if subject is None:
            subject = _("{} - Verification Code").format(config.APP_NAME)

        send_mail(
            subject,
            _email,
            "send_email_otp",
            user=current_user,
            code=session["mfa_email_code"]
        )
    except OSError as ose:
        current_app.logger.exception(ose)
        return False, 503, _("Failed to send the code to email.") + \
            "\n" + str(ose)

    message = _(
        "A verification code was sent to {}. Check your email and enter "
        "the code."
    ).format(_mask_email(_email))

    return True, 200, message


def _mask_email(_email: str) -> str:
    """

    Args:
        _email (str): Email address to be masked

    Returns:
        str: Masked email address
    """
    import re
    email_split = re.split('@', _email)
    username, domain = email_split
    domain_front, *domain_back_list = re.split('[.]', domain)
    users = re.split('[.]', username)

    def _mask_except_first_char(_str: str) -> str:
        """
        Mask all characters except first character of the input string.
        Args:
            _str (str): Input string to be masked

        Returns:
            str: Masked string
        """
        return _str[0] + '*' * (len(_str) - 1)

    return '.'.join([_mask_except_first_char(user) for user in users]) + \
        '@' + _mask_except_first_char(domain_front) + '.' + \
        '.'.join(domain_back_list)


def send_email_code() -> Response:
    """
    Send the code to the users' email address, stored during the registration.

    Raises:
        ValidationException: Raise this exception when user is not registered
        for this authentication method.

    Returns:
        Flask.Response: Response containing the HTML portion after sending the
                        code to the registered email address of the user.
    """

    options, found = fetch_auth_option(EMAIL_AUTH_METHOD)

    if found is False:
        raise ValidationException(_(
            "User has not registered for email authentication"
        ))

    success, http_code, message = _send_code_to_email(options)

    if success is False:
        return Response(message, http_code, mimetype='text/html')

    return dict(message=message)


@pgCSRFProtect.exempt
def javascript() -> Response:
    """
    Returns the javascript code for the email authentication method.

    Returns:
        Flask.Response: Response object conataining the javscript code for the
                        email auth method.
    """
    if not current_user.is_authenticated:
        return Response(_("Not accessible"), 401, mimetype="text/plain")

    return Response(render_template(
        "mfa/email.js", _=_, url_for=url_for,
    ), 200, mimetype="text/javascript")


EMAIL_AUTH_METHOD = 'email'


def email_authentication_label():
    return _('Email Authentication')


class EmailAuthentication(BaseMFAuth):

    @property
    def name(self):
        return EMAIL_AUTH_METHOD

    @property
    def label(self):
        return email_authentication_label()

    def validate(self, **kwargs):
        code = kwargs.get('code', None)
        email_otp = session.get("mfa_email_code", None)
        if code is not None and email_otp is not None and code == email_otp:
            session.pop("mfa_email_code")
            return
        raise ValidationException("Invalid code")

    def validation_view(self):
        session.pop("mfa_email_code", None)
        return dict(
            description=_("Verify with Email Authentication"),
            button_label=_("Send Code"),
            button_label_sending=_("Sending Code...")
        )

    def _registration_view(self):
        email = getattr(current_user, 'email', '')
        return dict(
            label=email_authentication_label(),
            auth_method=EMAIL_AUTH_METHOD,
            description=_("Enter the email address to send a code"),
            email_address_placeholder=_("Email address"),
            email_address=email,
            note_label=_("Note"),
            note=_(
                "This email address will only be used for two factor "
                "authentication purposes. The email address for the user "
                "account will not be changed."
            ),
        )

    def _registration_view_after_code_sent(self, _form_data):

        session['mfa_email_id'] = _form_data.get('send_to', None)
        success, http_code, message = _send_code_to_email(
            session['mfa_email_id']
        )

        if success is False:
            flash(message, MessageType.ERROR)
            return None

        return dict(
            label=email_authentication_label(),
            auth_method=EMAIL_AUTH_METHOD,
            message=message,
            otp_placeholder=_("Enter code here")
        )

    def registration_view(self, _form_data):

        if 'validate' in _form_data:
            if _form_data['validate'] == 'send_code':
                return self._registration_view_after_code_sent(_form_data)

            code = _form_data.get('code', 'unknown')

            if code is not None and \
                    code == session.get("mfa_email_code", None) and \
                    session.get("mfa_email_id", None) is not None:
                mfa_add(EMAIL_AUTH_METHOD, session['mfa_email_id'])

                flash(_(
                    "Email Authentication registered successfully."
                ), MessageType.SUCCESS)

                session.pop('mfa_email_code', None)

                return None

            flash(_('Invalid code'), MessageType.ERROR)

        return self._registration_view()

    def register_url_endpoints(self, blueprint):
        blueprint.add_url_rule(
            "/send_email_code", "send_email_code", send_email_code,
            methods=("POST", )
        )
        blueprint.add_url_rule(
            "/email.js", "email_js", javascript, methods=("GET", )
        )

    @property
    def icon(self):
        return url_for("mfa.static", filename="images/email_lock.svg")

    @property
    def validate_script(self):
        return url_for("mfa.email_js")

我已经安装并安装了 Flask_security 包并发送电子邮件 我想按照在我的笔记本电脑上运行 pgadmin4 服务器模式的过程

https://www.pgadmin.org/docs/pgadmin4/development/server_deployment.html#apache-httpd-configuration-windows

他们要求 运行以下命令创建配置数据库: python setup.py

有人可以帮助我吗?

python python-3.x postgresql flask pgadmin
1个回答
1
投票

这是版本 4.0.0rc2

上的旧删除

发布 2021 年 1 月 18 日

作为 Flask-Security 初始化一部分的 send_mail_tasksend_mail 方法已被删除并替换为新的 MailUtil 类。实用方法 send_mail() 仍然可以使用。

如果您的应用程序没有使用任何已弃用的方法,那么唯一需要的更改是将 Flask-Mail 添加到您的包要求中(因为 Flask-Security 不再列出它)。请参阅电子邮件以获取更新的示例。

https://flask-security-too.readthedocs.io/en/stable/changelog.html#id24

那么,

from flask_security import send_mail

将会生成

ImportError: cannot import name 'send_mail' from 'flask_security'
© www.soinside.com 2019 - 2024. All rights reserved.