mirror of
https://github.com/frappe/erpnext.git
synced 2026-10-29 22:57:42 +00:00
fix(crm): keep the visitor session and site host on appointment verification
(cherry picked from commit 48f93fdd03)
This commit is contained in:
@@ -197,7 +197,7 @@ class Appointment(Document):
|
||||
frappe.sendmail(
|
||||
recipients=[self.customer_email],
|
||||
template=template,
|
||||
args={"full_name": self.customer_name, "site_url": frappe.utils.get_url(), **args},
|
||||
args={"full_name": self.customer_name, "site_url": get_url(allow_header_override=False), **args},
|
||||
subject=subject,
|
||||
**kwargs,
|
||||
)
|
||||
@@ -343,7 +343,7 @@ class Appointment(Document):
|
||||
|
||||
def _get_verify_url(self):
|
||||
key = self.generate_verification_key()
|
||||
return get_url("/book_appointment/verify?" + urlencode({"key": key}))
|
||||
return get_url("/book_appointment/verify?" + urlencode({"key": key}), allow_header_override=False)
|
||||
|
||||
def generate_verification_key(self):
|
||||
# store only the hash; the raw key lives solely in the emailed link
|
||||
|
||||
@@ -213,6 +213,30 @@ class TestAppointment(FrappeTestCase):
|
||||
stored = frappe.db.get_value("Appointment", appointment.name, "verification_token")
|
||||
self.assertEqual(stored, sha256_hash(params["key"]))
|
||||
|
||||
def test_verification_keeps_the_visitor_session(self):
|
||||
appointment = self._create_portal_appointment("portal_visitor_session@example.com")
|
||||
_parsed, params = parse_verify_url(appointment._get_verify_url())
|
||||
self.addCleanup(frappe.set_user, frappe.session.user)
|
||||
|
||||
frappe.set_user("test@example.com")
|
||||
frappe.local.session.data = frappe._dict(csrf_token="token")
|
||||
session = frappe.local.session
|
||||
with patch.object(Appointment, "send_appointment_confirmed_email"):
|
||||
frappe.local.form_dict = frappe._dict(params)
|
||||
context = verify_index.get_context(frappe._dict())
|
||||
frappe.local.flags.commit = False
|
||||
|
||||
self.assertTrue(context.success)
|
||||
self.assertIs(frappe.local.session, session)
|
||||
self.assertEqual((session.user, session.data.csrf_token), ("test@example.com", "token"))
|
||||
|
||||
def test_verify_url_ignores_the_request_host(self):
|
||||
appointment = self._create_portal_appointment("portal_visitor_host@example.com")
|
||||
self.addCleanup(setattr, frappe.local, "request", getattr(frappe.local, "request", None))
|
||||
set_request(method="GET", path="/book_appointment", headers={"Host": "attacker.example"})
|
||||
|
||||
self.assertNotIn("attacker.example", appointment._get_verify_url())
|
||||
|
||||
def test_email_verification_within_expiry_window(self):
|
||||
# Link used within the validity window - verification succeeds and the
|
||||
# appointment gets linked, assigned and added to the calendar
|
||||
|
||||
@@ -48,11 +48,14 @@ def get_context(context):
|
||||
def verify_appointment(appointment):
|
||||
# the signed link is the authorization; materializing the appointment
|
||||
# (agent assignment) needs system privileges the Guest visitor lacks
|
||||
visitor = frappe.session.user
|
||||
# switch on a detached session so the visitor's own session data is left untouched
|
||||
session = frappe.local.session
|
||||
frappe.local.session = frappe._dict()
|
||||
try:
|
||||
frappe.set_user("Administrator")
|
||||
appointment.email_verified = True
|
||||
appointment.status = "Open"
|
||||
appointment.save(ignore_permissions=True)
|
||||
finally:
|
||||
frappe.set_user(visitor)
|
||||
frappe.set_user(session.user)
|
||||
frappe.local.session = session
|
||||
|
||||
Reference in New Issue
Block a user