@arnaudw38/nodebb-plugin-spam-be-gone 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [1.0.7] - 2026-02-25
6
+
7
+ ### Fixed
8
+ - Login retry Turnstile reset now uses native event listeners only (removed jQuery delegated login listeners).
9
+ - Prevented duplicate retry-reset triggers caused by mixed jQuery + native listeners on some NodeBB themes.
10
+
11
+ ### Changed
12
+ - Simplified login retry detection to click + Enter key flows (removed submit listener).
13
+
14
+ ## [1.0.6] - 2026-02-25
15
+
16
+ ### Fixed
17
+ - Fixed login retry Turnstile reset trigger on NodeBB login flows that do not emit the expected jQuery submit/click events.
18
+ - Prevented missing reset after failed login without page reload by adding capture-phase submit/click/Enter listeners.
19
+
5
20
  ## [1.0.5] - 2026-02-25
6
21
 
7
22
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnaudw38/nodebb-plugin-spam-be-gone",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "Anti-spam plugin for NodeBB 4.x using Akismet, StopForumSpam API, ProjectHoneyPot, and Cloudflare Turnstile (Turnstile-only fork)",
5
5
  "main": "library.js",
6
6
  "scripts": {},
@@ -8,6 +8,7 @@ $(function () {
8
8
  var turnstileState = {
9
9
  widgets: {},
10
10
  loginBindingsAttached: false,
11
+ loginResetTimers: [],
11
12
  };
12
13
 
13
14
  function getTurnstileArgs() {
@@ -52,19 +53,23 @@ $(function () {
52
53
  function scheduleLoginTurnstileReset(targetId) {
53
54
  // Turnstile tokens are single-use. On failed login, NodeBB keeps the user on the
54
55
  // same page, so we refresh the widget shortly after submit to allow a retry.
55
- [1200, 3000].forEach(function (delay) {
56
- window.setTimeout(function () {
57
- if (ajaxify.data && ajaxify.data.template && ajaxify.data.template.name && ajaxify.data.template.name !== 'login') {
56
+ turnstileState.loginResetTimers.forEach(function (timerId) {
57
+ window.clearTimeout(timerId);
58
+ });
59
+ turnstileState.loginResetTimers = [];
60
+
61
+ [1000, 2200, 4000].forEach(function (delay) {
62
+ var timerId = window.setTimeout(function () {
63
+ var onLoginPage = !ajaxify.data || !ajaxify.data.tpl_url || ajaxify.data.tpl_url === 'login';
64
+ if (!onLoginPage) {
58
65
  return;
59
66
  }
60
67
  if (!document.getElementById(targetId)) {
61
68
  return;
62
69
  }
63
- // Reset unconditionally if we're still on the login page after submit.
64
- // Tokens are single-use and may already have been cleared by the form logic
65
- // when a login attempt fails, so checking the hidden input is unreliable.
66
70
  resetTurnstileWidget(targetId);
67
71
  }, delay);
72
+ turnstileState.loginResetTimers.push(timerId);
68
73
  });
69
74
  }
70
75
 
@@ -74,16 +79,32 @@ $(function () {
74
79
  }
75
80
  turnstileState.loginBindingsAttached = true;
76
81
 
77
- $(document)
78
- .off('submit.spamBeGoneTurnstileLogin')
79
- .on('submit.spamBeGoneTurnstileLogin', 'form[action="/login"], form[data-action="login"], #login', function () {
80
- scheduleLoginTurnstileReset(targetId);
81
- })
82
- .off('click.spamBeGoneTurnstileLogin')
83
- .on('click.spamBeGoneTurnstileLogin', '[component="login/submit"]', function () {
84
- scheduleLoginTurnstileReset(targetId);
85
- })
86
- .off('input.spamBeGoneTurnstileLogin change.spamBeGoneTurnstileLogin');
82
+ function loginSubmitTrigger() {
83
+ scheduleLoginTurnstileReset(targetId);
84
+ }
85
+
86
+ // Native capture listeners only (avoid duplicate handlers/race conditions with jQuery delegates).
87
+ document.addEventListener('click', function (ev) {
88
+ var btn = ev.target && ev.target.closest ? ev.target.closest('[component="login/submit"], #login [type="submit"], form[action*="/login"] [type="submit"]') : null;
89
+ if (btn) {
90
+ loginSubmitTrigger();
91
+ }
92
+ }, true);
93
+
94
+ // Enter key in login fields for themes that trigger login without a click event.
95
+ document.addEventListener('keydown', function (ev) {
96
+ if (ev.key !== 'Enter') {
97
+ return;
98
+ }
99
+ var el = ev.target;
100
+ if (!el || !el.closest) {
101
+ return;
102
+ }
103
+ var inLogin = el.closest('#login, form[action*="/login"], form[data-action="login"]');
104
+ if (inLogin) {
105
+ loginSubmitTrigger();
106
+ }
107
+ }, true);
87
108
  }
88
109
 
89
110
  function renderTurnstileIfNeeded(isLoginPage) {