mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-11-02 20:30:17 -06:00
The same email or username may belong to accounts from several auth sources. Flask-Security looks the account up by email alone, and took whichever row came first: - Internal login checked the password against that row, so an internal user could not log in when an LDAP or OAuth2 account with the same email was found first. Flask-Security's lookup now prefers the internal account; ignoring case, it prefers the one matching exactly, then the oldest. A missing email or username identifies no account. - A password reset was sent for whichever account had the email, and a reset token for an account from another source was accepted, giving it a local password and logging it in. Reset instructions are now sent for the internal account, and a token for any other account is refused. - The About box showed the configuration to any user whose email was that of an administrator's account, whatever its source. It now checks the user's own role. The test runner excluded every test module whose name started with one on its desktop mode list, so excluding test_reset_password also excluded test_reset_password_auth_source. Each entry now excludes only the module it names, and the server mode only modules are listed.
144 lines
4.5 KiB
Python
144 lines
4.5 KiB
Python
##########################################################################
|
|
#
|
|
# pgAdmin 4 - PostgreSQL Tools
|
|
#
|
|
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
|
|
# This software is released under the PostgreSQL Licence
|
|
#
|
|
##########################################################################
|
|
|
|
"""A blueprint module implementing the about box."""
|
|
|
|
from flask import Response, render_template, request
|
|
from flask_babel import gettext
|
|
from flask_security import current_user
|
|
from pgadmin.user_login_check import pga_login_required
|
|
from pgadmin.utils import PgAdminModule
|
|
from pgadmin.utils.menu import MenuItem
|
|
from pgadmin.utils.constants import MIMETYPE_APP_JS
|
|
from pgadmin.utils.ajax import make_json_response
|
|
import config
|
|
from user_agents import parse
|
|
import platform
|
|
import re
|
|
import sys
|
|
|
|
MODULE_NAME = 'about'
|
|
|
|
|
|
class AboutModule(PgAdminModule):
|
|
def get_own_menuitems(self):
|
|
appname = config.APP_NAME
|
|
|
|
return {
|
|
'help_items': [
|
|
MenuItem(
|
|
name='mnu_about',
|
|
priority=999,
|
|
module="pgAdmin.About",
|
|
callback='about_show',
|
|
icon='fa fa-info-circle',
|
|
label=gettext('About %(appname)s', appname=appname)
|
|
)
|
|
]
|
|
}
|
|
|
|
def get_exposed_url_endpoints(self):
|
|
return ['about.index']
|
|
|
|
|
|
blueprint = AboutModule(MODULE_NAME, __name__, static_url_path='')
|
|
|
|
|
|
##########################################################################
|
|
# A test page
|
|
##########################################################################
|
|
@blueprint.route("/", endpoint='index')
|
|
@pga_login_required
|
|
def index():
|
|
"""Render the about box."""
|
|
info = {}
|
|
# Get OS , NW.js, Browser details
|
|
browser, os_details, electron_version = detect_browser(request)
|
|
admin = current_user.has_role('Administrator')
|
|
|
|
if electron_version:
|
|
info['electron'] = electron_version
|
|
|
|
if config.SERVER_MODE:
|
|
info['app_mode'] = gettext('Server')
|
|
else:
|
|
info['app_mode'] = gettext('Desktop')
|
|
|
|
info['commit_hash'] = getattr(config, 'COMMIT_HASH', None)
|
|
info['browser_details'] = browser
|
|
info['version'] = config.APP_VERSION
|
|
info['admin'] = admin
|
|
info['current_user'] = current_user.email
|
|
info['python_version'] = sys.version.split(" ", maxsplit=1)[0]
|
|
|
|
if admin:
|
|
settings = ""
|
|
info['os_details'] = os_details
|
|
info['log_file'] = config.LOG_FILE
|
|
|
|
# If external datbase is used do not display SQLITE_PATH
|
|
if not config.CONFIG_DATABASE_URI:
|
|
info['config_db'] = config.SQLITE_PATH
|
|
|
|
for setting in dir(config):
|
|
if not setting.startswith('_') and setting.isupper() and \
|
|
setting not in ['CSRF_SESSION_KEY',
|
|
'SECRET_KEY',
|
|
'SECURITY_PASSWORD_SALT',
|
|
'SECURITY_PASSWORD_HASH',
|
|
'ALLOWED_HOSTS',
|
|
'MAIL_PASSWORD',
|
|
'LDAP_BIND_PASSWORD',
|
|
'SECURITY_PASSWORD_HASH']:
|
|
if isinstance(getattr(config, setting), str):
|
|
settings = \
|
|
settings + '{} = "{}"\n'.format(
|
|
setting, getattr(config, setting))
|
|
else:
|
|
settings = \
|
|
settings + '{} = {}\n'.format(
|
|
setting, getattr(config, setting))
|
|
|
|
info['settings'] = settings
|
|
|
|
return make_json_response(
|
|
data=info,
|
|
status=200
|
|
)
|
|
|
|
|
|
def detect_browser(request):
|
|
"""This function returns the browser and os details"""
|
|
electron_version = None
|
|
agent = request.environ.get('HTTP_USER_AGENT')
|
|
|
|
try:
|
|
# available only for python 3.10 and above
|
|
os_release = platform.freedesktop_os_release()
|
|
os_details = os_release.get('PRETTY_NAME', '')
|
|
if os_details:
|
|
os_details += ', '
|
|
except Exception as _:
|
|
os_details = ''
|
|
|
|
os_details += parse(platform.platform()).ua_string
|
|
|
|
if 'Electron' in agent:
|
|
electron_version = re.findall('Electron/([\\d.]+\\d+)', agent)[0]
|
|
|
|
browser = re.findall(
|
|
'(opera|chrome|safari|firefox|msie|trident(?=/))/?\\s*([\\d.]+\\d+)',
|
|
agent, re.IGNORECASE)
|
|
if not browser:
|
|
browser = agent.split('/')[0]
|
|
else:
|
|
browser = " ".join(browser[0])
|
|
|
|
return browser, os_details, electron_version
|