in gui/backend/gui_plugin/core/ShellGuiWebSocketHandler.py [0:0]
def execute_command_request(self, json_msg):
request_id = json_msg.get('request_id')
try:
cmd = json_msg.get('command')
if not cmd:
raise Exception(
'No command given. Please provide the command.')
# Check if user is allowed to execute this command
allowed = False
res = self.db.execute(
'''SELECT p.name, p.access_pattern
FROM privilege p
INNER JOIN role_has_privilege r_p
ON p.id = r_p.privilege_id
INNER JOIN user_has_role u_r
ON r_p.role_id = u_r.role_id
WHERE u_r.user_id = ? AND p.privilege_type_id = 1''',
(self.session_user_id,)).fetch_all()
for row in res:
p = re.compile(row['access_pattern'])
m = p.match(cmd)
if not m:
raise Exception(f'This user account has no privileges to '
f'execute the command {cmd}')
allowed = True
break
if not allowed:
raise Exception(f'This user does not have the necessary '
f'privileges to execute the command {cmd}.')
# Argument need to be passed in a dict using the argument names as
# the keys
args = json_msg.get('args', {})
kwargs = json_msg.get('kwargs', {})
kwargs = {**args, **kwargs}
# Inspect the function arguments and check if there are arguments
# named user_id, profile_id, web_session, request_id,
# module_session, async_web_session or session.
# If so, replace them with session variables
f_args = []
# Loop over all chained objects/functions of the given cmd and find
# the function to call
matches = re.findall(r'(\w+)\.', cmd + '.')
parent_obj = None
func = None
if len(matches) < 2:
raise Exception(
f"The command '{cmd}' is using wrong format. "
"Use <global>[.<object>]*.<function>")
# Last entry is a function name
function_name = matches[-1]
# Rest is a chain of objects
objects = matches[:-1]
found_objects = []
# Selects the parent object
if objects[0] == 'gui':
parent_obj = gui
objects = objects[1:]
found_objects.append('gui')
else:
parent_obj = mysqlsh.globals
# Searches the object hierarchy
for object in objects:
try:
# Convert from camelCase to snake_case
object = re.sub(r'(?<!^)(?=[A-Z])', '_', object).lower()
child = getattr(parent_obj, object)
# Set the parent_obj for the next object evaluation
parent_obj = child
found_objects.append(object)
except:
if len(found_objects) == 0:
raise Exception(
f"The '{object}' global object does not exist")
else:
raise Exception(
f"Object '{'.'.join(found_objects)}' has no member named '{object}'")
# Searches the target function
try:
func = getattr(parent_obj, function_name)
except:
raise Exception(
f"Object '{'.'.join(found_objects)}' has no member function named '{function_name}'")
f_args = {}
if func:
f_args = self.get_function_arguments(
func=func, mod=parent_obj, mod_cmd=function_name)
lock_session = False
if found_objects[0] == 'gui':
# This is the `user_id` that needs to be provided by the user
# like for the function `add_profile(user_id, profile)`
if "user_id" in f_args:
# Return error if user_id does not match self.session_user_id
if self.session_user_id is None or "user_id" not in kwargs \
or kwargs["user_id"] != self.session_user_id:
raise Exception(f'The function argument user_id must not '
f'be set to a different user_id than the '
f'one used in the '
f'authenticated session.')
kwargs.update({"user_id": self.session_user_id})
# The `_user_id` here is for internal use only
# it's not exposed to the user and it's replaced
# always by session_user_id
if "_user_id" in f_args and not self.is_local_session:
kwargs.update({"_user_id": self.session_user_id})
if "profile_id" in f_args:
if "profile_id" not in kwargs:
kwargs.update({"profile_id":
self.session_active_profile_id})
if "web_session" in f_args:
raise Exception(
f'Argument web_session not allowed for function: {cmd}.')
if "request_id" in f_args:
raise Exception(
f'Argument request_id not allowed for function: {cmd}.')
if "be_session" in f_args:
kwargs.update({"be_session": self.db})
if "db_connection_id" in f_args and self.single_server is not None:
if self._single_server_conn_id is None:
if self.session_uuid in self.get_cache():
self._single_server_conn_id = self.get_cache()[
self.session_uuid][1]
del self.get_cache()[
self.session_uuid]
kwargs.update({"db_connection_id": self._single_server_conn_id})
if "interactive" in f_args:
kwargs.update({"interactive": False})
# If the function may receive a message handler, adds the kwarg so the
# RequestHandler properly sets the callback
if "send_gui_message" in f_args:
kwargs.update({"send_gui_message": True})
lock_session = False
if "session" in f_args:
# If the called function requires a session parameter,
# get it from the given module_session
if not 'module_session_id' in kwargs:
raise Exception(
f'The function {cmd} requires the module_session_id '
'argument to be set.')
module_session = self.get_module_session_object(
kwargs['module_session_id'])
if not isinstance(module_session, DbModuleSession):
raise Exception(
f'The function {cmd} needs a module_session_id '
'argument set to a DbModuleSession.')
user_session_functions = ["gui.sql_editor.execute",
"gui.sql_editor.default_user_schema", "gui.sql_editor.get_current_schema",
"gui.sql_editor.set_current_schema", "gui.sql_editor.get_auto_commit",
"gui.sql_editor.set_auto_commit"]
if isinstance(module_session, SqlEditorModuleSession) and cmd in user_session_functions:
db_module_session = module_session._db_user_session
else:
db_module_session = module_session._db_service_session
if not isinstance(db_module_session, DbSession):
raise Exception(
f'The function {cmd} needs a module_session_id '
'argument set to a DbSession.')
self.register_module_request(
request_id, kwargs['module_session_id'])
kwargs.update({"session": db_module_session})
# The plugins written for the Shell that work with standard Shell session fall on this branch,
# the session must be locked while the function is executed to avoid race conditions that may
# lead to shell failures
if found_objects[0] != 'gui':
lock_session = True
del kwargs['module_session_id']
module_session = None
if "module_session" in f_args:
if "module_session_id" not in kwargs:
raise Exception('No module_session_id given. Please '
'provide the module_session_id.')
# swap 'module_session_id' with 'module_session'
module_session = self.get_module_session_object(
kwargs['module_session_id'])
kwargs.update({"module_session": module_session})
self.register_module_request(
request_id, kwargs['module_session_id'])
del kwargs['module_session_id']
thread = RequestHandler(
request_id, func, kwargs, self, lock_session=lock_session)
thread.start()
result = None
except Exception as e:
logger.exception(e)
result = Response.exception(e)
if result is not None:
self.send_command_response(request_id, result)