diff --git a/frappe/tests/test_email.py b/frappe/tests/test_email.py index 13e95c38e6..de0fe00012 100644 --- a/frappe/tests/test_email.py +++ b/frappe/tests/test_email.py @@ -310,6 +310,20 @@ class TestEmail(FrappeTestCase): email_account.enable_incoming = False +class TestVerifiedRequests(FrappeTestCase): + def test_round_trip(self): + from frappe.utils import set_request + from frappe.utils.verified_command import get_signed_params, verify_request + + test_cases = [{"xyz": "abc"}, {"email": "a@b.com", "user": "xyz"}] + + for params in test_cases: + signed_url = get_signed_params(params) + set_request(method="GET", path="?" + signed_url) + self.assertTrue(verify_request()) + frappe.local.request = None + + if __name__ == "__main__": import unittest diff --git a/frappe/utils/verified_command.py b/frappe/utils/verified_command.py index b25e646cf5..3d6346276d 100644 --- a/frappe/utils/verified_command.py +++ b/frappe/utils/verified_command.py @@ -16,9 +16,8 @@ def get_signed_params(params): if not isinstance(params, str): params = urlencode(params) - signature = hmac.new(params.encode(), digestmod=hashlib.sha512) - signature.update(get_secret().encode()) - return params + "&_signature=" + signature.hexdigest() + signature = _sign_message(params) + return params + "&_signature=" + signature def get_secret(): @@ -35,12 +34,10 @@ def verify_request(): signature_string = "&_signature=" if signature_string in query_string: - params, signature = query_string.split(signature_string) + params, given_signature = query_string.split(signature_string) - given_signature = hmac.new(params.encode("utf-8"), digestmod=hashlib.sha512) - - given_signature.update(get_secret().encode()) - valid_signature = hmac.compare_digest(signature, given_signature.hexdigest()) + computed_signature = _sign_message(params) + valid_signature = hmac.compare_digest(given_signature, computed_signature) valid_method = frappe.request.method == "GET" valid_request_data = not (frappe.request.form or frappe.request.data) @@ -55,6 +52,10 @@ def verify_request(): return False +def _sign_message(message: str) -> str: + return hmac.new(get_secret().encode(), message.encode(), digestmod=hashlib.sha512).hexdigest() + + def get_url(cmd, params, nonce=None, secret=None): if not nonce: nonce = params