Repository: dgtlmoon/changedetection.io (language: python)

Issue:
Add to ignore list from text preview not communicating with server
**Describe the bug**
highlighting text in text preview to add to ignore list results in a "There was an error communicating with the server." error message and then "There was a problem processing the request, please reload the page." message.

Post request `http://192.168.1.20:5000/highlight_submit_ignore_url?uuid=627bf340-b968-450a-8c0d-c0f59bc51ee5` receives `400 Bad Request The CSRF token is invalid` from the server

**Version**
v0.45.24

**To Reproduce**

Steps to reproduce the behavior:
1. Go to Preview -> Text
2. Highlight any text
3. click "ignore exact text"
4. See error

! ALWAYS INCLUDE AN EXAMPLE URL WHERE IT IS POSSIBLE TO RE-CREATE THE ISSUE - USE THE 'SHARE WATCH' FEATURE AND PASTE IN THE SHARE-LINK!

**Expected behavior**
No error message and text added to ignore list

**Screenshots**
n/a

**Desktop (please complete the following information):**
 - OS: Windows 11 Version 23H2
 - Browser Vivaldi
 - Version 6.8.3381.46 (Stable channel) (64-bit) 
also
- Browser Chrome
- Version 126.0.6478.127 (Official Build) (64-bit)
also
- Browser Firefox
- Version 127.0.2 (64-bit)


Discussion / hints:
I have the same issue. "add to ignore" just works from "Diff" Page. 

Fix patch:
diff --git a/changedetectionio/static/js/browser-steps.js b/changedetectionio/static/js/browser-steps.js
index 4e576bd456c..5c5fc52a5b8 100644
--- a/changedetectionio/static/js/browser-steps.js
+++ b/changedetectionio/static/js/browser-steps.js
@@ -1,14 +1,5 @@
 $(document).ready(function () {
 
-    // duplicate
-    var csrftoken = $('input[name=csrf_token]').val();
-    $.ajaxSetup({
-        beforeSend: function (xhr, settings) {
-            if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
-                xhr.setRequestHeader("X-CSRFToken", csrftoken)
-            }
-        }
-    })
     var browsersteps_session_id;
     var browser_interface_seconds_remaining = 0;
     var apply_buttons_disabled = false;
diff --git a/changedetectionio/static/js/csrf.js b/changedetectionio/static/js/csrf.js
new file mode 100644
index 00000000000..4e2aca53445
--- /dev/null
+++ b/changedetectionio/static/js/csrf.js
@@ -0,0 +1,10 @@
+$(document).ready(function () {
+    $.ajaxSetup({
+        beforeSend: function (xhr, settings) {
+            if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
+                xhr.setRequestHeader("X-CSRFToken", csrftoken)
+            }
+        }
+    })
+});
+
diff --git a/changedetectionio/static/js/diff-overview.js b/changedetectionio/static/js/diff-overview.js
index 95e6dd7a0b5..1f501529dcf 100644
--- a/changedetectionio/static/js/diff-overview.js
+++ b/changedetectionio/static/js/diff-overview.js
@@ -1,13 +1,4 @@
 $(document).ready(function () {
-    var csrftoken = $('input[name=csrf_token]').val();
-    $.ajaxSetup({
-        beforeSend: function (xhr, settings) {
-            if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
-                xhr.setRequestHeader("X-CSRFToken", csrftoken)
-            }
-        }
-    })
-
     $('.needs-localtime').each(function () {
         for (var option of this.options) {
             var dateObject = new Date(option.value * 1000);
@@ -48,6 +39,12 @@ $(document).ready(function () {
       $("#highlightSnippet").remove();
     }
 
+    // Listen for Escape key press
+    window.addEventListener('keydown', function (e) {
+        if (e.key === 'Escape') {
+            clean();
+        }
+    }, false);
 
     function dragTextHandler(event) {
         console.log('mouseupped');
diff --git a/changedetectionio/static/js/notifications.js b/changedetectionio/static/js/notifications.js
index d3a0b81a774..95f3eacf4bd 100644
--- a/changedetectionio/static/js/notifications.js
+++ b/changedetectionio/static/js/notifications.js
@@ -13,16 +13,6 @@ $(document).ready(function() {
   $('#send-test-notification').click(function (e) {
     e.preventDefault();
 
-    // this can be global
-    var csrftoken = $('input[name=csrf_token]').val();
-    $.ajaxSetup({
-        beforeSend: function(xhr, settings) {
-            if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
-                xhr.setRequestHeader("X-CSRFToken", csrftoken)
-            }
-        }
-    })
-
     data = {
       notification_body: $('#notification_body').val(),
       notification_format: $('#notification_format').val(),
diff --git a/changedetectionio/templates/base.html b/changedetectionio/templates/base.html
index 87018a7dee8..27ce8419df6 100644
--- a/changedetectionio/templates/base.html
+++ b/changedetectionio/templates/base.html
@@ -26,7 +26,11 @@
     <meta name="msapplication-TileColor" content="#da532c">
     <meta name="msapplication-config" content="favicons/browserconfig.xml">
     <meta name="theme-color" content="#ffffff">
+    <script>
+        const csrftoken="{{ csrf_token() }}";
+    </script>
     <script src="{{url_for('static_content', group='js', filename='jquery-3.6.0.min.js')}}"></script>
+    <script src="{{url_for('static_content', group='js', filename='csrf.js')}}" defer></script>
   </head>
 
   <body>
diff --git a/requirements.txt b/requirements.txt
index ae099de46d2..44049fb21b2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -83,4 +83,4 @@ jsonschema==4.17.3
 
 loguru
 # Needed for > 3.10, https://github.com/microsoft/playwright-python/issues/2096
-greenlet >= 3.0.3
\ No newline at end of file
+greenlet >= 3.0.3


Test patch:
diff --git a/changedetectionio/tests/test_ignorehighlighter.py b/changedetectionio/tests/test_ignorehighlighter.py
index 88bd0af61db..521638456c6 100644
--- a/changedetectionio/tests/test_ignorehighlighter.py
+++ b/changedetectionio/tests/test_ignorehighlighter.py
@@ -45,7 +45,6 @@ def test_highlight_ignore(client, live_server):
     )
 
     res = client.get(url_for("edit_page", uuid=uuid))
-
     # should be a regex now
     assert b'/oh\ yeah\ \d+/' in res.data
 
@@ -55,3 +54,7 @@ def test_highlight_ignore(client, live_server):
     # And it should register in the preview page
     res = client.get(url_for("preview_page", uuid=uuid))
     assert b'<div class="ignored">oh yeah 456' in res.data
+
+    # Should be in base.html
+    assert b'csrftoken' in res.data
+