Source code for tcms.rpc.handlers
import html
from datetime import timedelta
from modernrpc.exceptions import RPCInvalidRequest
from modernrpc.jsonrpc.handler import JsonRpcHandler
from modernrpc.xmlrpc.handler import XmlRpcHandler
[docs]
class KiwiTCMSHandlerMixin:
[docs]
@staticmethod
def escape_value(value):
if isinstance(value, str):
return html.escape(value)
if isinstance(value, timedelta):
return value.total_seconds()
return value
[docs]
@staticmethod
def escape(value):
"""Recursively walk *value* and transform it in place."""
if isinstance(value, dict):
for key, val in value.items():
value[key] = __class__.escape(val)
elif isinstance(value, list):
for idx, item in enumerate(value):
value[idx] = __class__.escape(item)
else:
return __class__.escape_value(value)
return value
[docs]
@staticmethod
def inspect_rpc_args(rpc_request):
if rpc_request.method_name.endswith(
".create"
) or rpc_request.method_name.endswith(".update"):
return
restricted_fields = (
"password",
"token",
"secret",
"activation_key",
"api_key",
"apikey",
)
keys_to_check = []
for arg in rpc_request.args:
if isinstance(arg, dict):
keys_to_check.extend(arg.keys())
kwargs = getattr(rpc_request, "kwargs", None)
if isinstance(kwargs, dict):
keys_to_check.extend(kwargs.keys())
for key in keys_to_check:
key_str = str(key).lower()
if any(key_str.find(field) > -1 for field in restricted_fields):
raise RPCInvalidRequest("Unsupported field")
[docs]
def process_single_request(self, rpc_request, context):
try:
self.inspect_rpc_args(rpc_request)
except Exception as exc: # pylint: disable=broad-exception-caught
rpc_exc = context.server.on_error(exc, context)
return self.build_error_result(
request=rpc_request,
code=rpc_exc.code,
message=rpc_exc.message,
data=rpc_exc.data,
)
return super().process_single_request(rpc_request, context)
[docs]
async def aprocess_single_request(self, rpc_request, context):
try:
self.inspect_rpc_args(rpc_request)
except Exception as exc: # pylint: disable=broad-exception-caught
rpc_exc = context.server.on_error(exc, context)
return self.build_error_result(
request=rpc_request,
code=rpc_exc.code,
message=rpc_exc.message,
data=rpc_exc.data,
)
return await super().aprocess_single_request(rpc_request, context)
[docs]
def build_success_result(self, request, data):
data = __class__.escape(data)
return super().build_success_result(request, data)
[docs]
class KiwiTCMSJsonRpcHandler(
KiwiTCMSHandlerMixin, JsonRpcHandler
): # pylint: disable=remove-empty-class
pass
[docs]
class KiwiTCMSXmlRpcHandler(
KiwiTCMSHandlerMixin, XmlRpcHandler
): # pylint: disable=remove-empty-class
pass