PageSourceSearch

https://www.bewhalewise.org/wp-content/plugins/akismet/_inc/akismet-frontend.js?ver=1777110811

js bewhalewise.org collected 2026-09-24 09:45:59 UTC 12,155 bytes, 393 lines download raw bytes

1/**
2 * Observe how the user enters content into the comment form in order to determine whether it's a bot or not.
3 *
4 * Note that no actual input is being saved here, only counts and timings between events.
5 */
6
7( function() {
8	// Passive event listeners are guaranteed to never call e.preventDefault(),
9	// but they're not supported in all browsers.  Use this feature detection
10	// to determine whether they're available for use.
11	var supportsPassive = false;
12
13	try {
14		var opts = Object.defineProperty( {}, 'passive', {
15			get : function() {
16				supportsPassive = true;
17			}
18		} );
19
20		window.addEventListener( 'testPassive', null, opts );
21		window.removeEventListener( 'testPassive', null, opts );
22	} catch ( e ) {}
23
24	function init() {
25		var input_begin = '';
26
27		var keydowns = {};
28		var lastKeyup = null;
29		var lastKeydown = null;
30		var keypresses = [];
31
32		var modifierKeys = [];
33		var correctionKeys = [];
34
35		var lastMouseup = null;
36		var lastMousedown = null;
37		var mouseclicks = [];
38		var mouseclickCoordinates = [];
39
40		var mousemoveTimer = null;
41		var lastMousemoveX = null;
42		var lastMousemoveY = null;
43		var mousemoveStart = null;
44		var mousemoves = [];
45
46		var touchmoveCountTimer = null;
47		var touchmoveCount = 0;
48
49		var lastTouchEnd = null;
50		var lastTouchStart = null;
51		var touchEvents = [];
52
53		var scrollCountTimer = null;
54		var scrollCount = 0;
55
56		var correctionKeyCodes = [ 'Backspace', 'Delete', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown' ];
57		var modifierKeyCodes = [ 'Shift', 'CapsLock' ];
58
59		var forms = document.querySelectorAll( 'form[method=post]' );
60
61		for ( var i = 0; i < forms.length; i++ ) {
62			var form = forms[i];
63
64			var formAction = form.getAttribute( 'action' );
65
66			// Ignore forms that POST directly to other domains; these could be things like payment forms.
67			if ( formAction ) {
68				// Check that the form is posting to an external URL, not a path.
69				if ( formAction.indexOf( 'http://' ) == 0 || formAction.indexOf( 'https://' ) == 0 ) {
70					if ( formAction.indexOf( 'http://' + window.location.hostname + '/' ) != 0 && formAction.indexOf( 'https://' + window.location.hostname + '/' ) != 0 ) {
71						continue;
72					}
73				}
74			}
75
76			form.addEventListener( 'submit', function () {
77				var ak_bkp = prepare_array_for_request( keypresses );
78				var ak_bmc = prepare_array_for_request( mouseclicks );
79				var ak_bte = prepare_array_for_request( touchEvents );
80				var ak_bmm = prepare_array_for_request( mousemoves );
81				var ak_bcc = prepare_array_for_request( mouseclickCoordinates );
82
83				var input_fields = {
84					// When did the user begin entering any input?
85					'bib': input_begin,
86
87					// When was the form submitted?
88					'bfs': Date.now(),
89
90					// How many keypresses did they make?
91					'bkpc': keypresses.length,
92
93					// How quickly did they press a sample of keys, and how long between them?
94					'bkp': ak_bkp,
95
96					// How quickly did they click the mouse, and how long between clicks?
97					'bmc': ak_bmc,
98
99					// How many mouseclicks did they make?
100					'bmcc': mouseclicks.length,
101
102					// When did they press modifier keys (like Shift or Capslock)?
103					'bmk': modifierKeys.join( ';' ),
104
105					// When did they correct themselves? e.g., press Backspace, or use the arrow keys to move the cursor back
106					'bck': correctionKeys.join( ';' ),
107
108					// How many times did they move the mouse?
109					'bmmc': mousemoves.length,
110
111					// How many times did they move around using a touchscreen?
112					'btmc': touchmoveCount,
113
114					// How many times did they scroll?
115					'bsc': scrollCount,
116
117					// How quickly did they perform touch events, and how long between them?
118					'bte': ak_bte,
119
120					// How many touch events were there?
121					'btec' : touchEvents.length,
122
123					// How quickly did they move the mouse, and how long between moves?
124					'bmm' : ak_bmm,
125
126					// Click coordinates
127					'bcc' : ak_bcc
128				};
129
130				var akismet_field_prefix = 'ak_';
131
132				if ( this.getElementsByClassName ) {
133					// Check to see if we've used an alternate field name prefix. We store this as an attribute of the container around some of the Akismet fields.
134					var possible_akismet_containers = this.getElementsByClassName( 'akismet-fields-container' );
135
136					for ( var containerIndex = 0; containerIndex < possible_akismet_containers.length; containerIndex++ ) {
137						var container = possible_akismet_containers.item( containerIndex );
138
139						if ( container.getAttribute( 'data-prefix' ) ) {
140							akismet_field_prefix = container.getAttribute( 'data-prefix' );
141							break;
142						}
143					}
144				}
145
146				for ( var field_name in input_fields ) {
147					var field = document.createElement( 'input' );
148					field.setAttribute( 'type', 'hidden' );
149					field.setAttribute( 'name', akismet_field_prefix + field_name );
150					field.setAttribute( 'value', input_fields[ field_name ] );
151					this.appendChild( field );
152				}
153			}, supportsPassive ? { passive: true } : false  );
154
155			form.addEventListener( 'keydown', function ( e ) {
156				// If you hold a key down, some browsers send multiple keydown events in a row.
157				// Ignore any keydown events for a key that hasn't come back up yet.
158				if ( e.key in keydowns ) {
159					return;
160				}
161
162				var keydownTime = ( new Date() ).getTime();
163				keydowns[ e.key ] = [ keydownTime ];
164
165				if ( ! input_begin ) {
166					input_begin = keydownTime;
167				}
168
169				// In some situations, we don't want to record an interval since the last keypress -- for example,
170				// on the first keypress, or on a keypress after focus has changed to another element. Normally,
171				// we want to record the time between the last keyup and this keydown. But if they press a
172				// key while already pressing a key, we want to record the time between the two keydowns.
173
174				var lastKeyEvent = Math.max( lastKeydown, lastKeyup );
175
176				if ( lastKeyEvent ) {
177					keydowns[ e.key ].push( keydownTime - lastKeyEvent );
178				}
179
180				lastKeydown = keydownTime;
181			}, supportsPassive ? { passive: true } : false  );
182
183			form.addEventListener( 'keyup', function ( e ) {
184				if ( ! ( e.key in keydowns ) ) {
185					// This key was pressed before this script was loaded, or a mouseclick happened during the keypress, or...
186					return;
187				}
188
189				var keyupTime = ( new Date() ).getTime();
190
191				if ( 'TEXTAREA' === e.target.nodeName || 'INPUT' === e.target.nodeName ) {
192					if ( -1 !== modifierKeyCodes.indexOf( e.key ) ) {
193						modifierKeys.push( keypresses.length - 1 );
194					} else if ( -1 !== correctionKeyCodes.indexOf( e.key ) ) {
195						correctionKeys.push( keypresses.length - 1 );
196					} else {
197						// ^ Don't record timings for keys like Shift or backspace, since they
198						// typically get held down for longer than regular typing.
199
200						var keydownTime = keydowns[ e.key ][0];
201
202						var keypress = [];
203
204						// Keypress duration.
205						keypress.push( keyupTime - keydownTime );
206
207						// Amount of time between this keypress and the previous keypress.
208						if ( keydowns[ e.key ].length > 1 ) {
209							keypress.push( keydowns[ e.key ][1] );
210						}
211
212						keypresses.push( keypress );
213					}
214				}
215
216				delete keydowns[ e.key ];
217
218				lastKeyup = keyupTime;
219			}, supportsPassive ? { passive: true } : false  );
220
221			form.addEventListener( "focusin", function ( e ) {
222				lastKeydown = null;
223				lastKeyup = null;
224				keydowns = {};
225			}, supportsPassive ? { passive: true } : false  );
226
227			form.addEventListener( "focusout", function ( e ) {
228				lastKeydown = null;
229				lastKeyup = null;
230				keydowns = {};
231			}, supportsPassive ? { passive: true } : false  );
232		}
233
234		document.addEventListener( 'mousedown', function ( e ) {
235			lastMousedown = ( new Date() ).getTime();
236
237			var mouseclickCoordinate = [];
238
239			var rect = e.target.getBoundingClientRect();
240			var relativeX = e.clientX - rect.left;
241			var relativeY = e.clientY - rect.top;
242
243			// Pixel offset of the click within the target element.
244			mouseclickCoordinate.push( Math.round( relativeX ) );
245			mouseclickCoordinate.push( Math.round( relativeY ) );
246
247			// Percentage offset of the click within the target element.
248			mouseclickCoordinate.push( rect.width > 0 ? Math.round( relativeX / rect.width * 100 ) : 0 );
249			mouseclickCoordinate.push( rect.height > 0 ? Math.round( relativeY / rect.height * 100 ) : 0 );
250
251			mouseclickCoordinates.push( mouseclickCoordinate );
252		}, supportsPassive ? { passive: true } : false  );
253
254		document.addEventListener( 'mouseup', function ( e ) {
255			if ( ! lastMousedown ) {
256				// If the mousedown happened before this script was loaded, but the mouseup happened after...
257				return;
258			}
259
260			var now = ( new Date() ).getTime();
261
262			var mouseclick = [];
263			mouseclick.push( now - lastMousedown );
264
265			if ( lastMouseup ) {
266				mouseclick.push( lastMousedown - lastMouseup );
267			}
268
269			mouseclicks.push( mouseclick );
270
271			lastMouseup = now;
272
273			// If the mouse has been clicked, don't record this time as an interval between keypresses.
274			lastKeydown = null;
275			lastKeyup = null;
276			keydowns = {};
277		}, supportsPassive ? { passive: true } : false  );
278
279		document.addEventListener( 'mousemove', function ( e ) {
280			if ( mousemoveTimer ) {
281				clearTimeout( mousemoveTimer );
282				mousemoveTimer = null;
283			}
284			else {
285				mousemoveStart = ( new Date() ).getTime();
286				lastMousemoveX = e.offsetX;
287				lastMousemoveY = e.offsetY;
288			}
289
290			mousemoveTimer = setTimeout( function ( theEvent, originalMousemoveStart ) {
291				var now = ( new Date() ).getTime() - 500; // To account for the timer delay.
292
293				var mousemove = [];
294				mousemove.push( now - originalMousemoveStart );
295				mousemove.push(
296					Math.round(
297						Math.sqrt(
298							Math.pow( theEvent.offsetX - lastMousemoveX, 2 ) +
299							Math.pow( theEvent.offsetY - lastMousemoveY, 2 )
300						)
301					)
302				);
303
304				if ( mousemove[1] > 0 ) {
305					// If there was no measurable distance, then it wasn't really a move.
306					mousemoves.push( mousemove );
307				}
308
309				mousemoveStart = null;
310				mousemoveTimer = null;
311			}, 500, e, mousemoveStart );
312		}, supportsPassive ? { passive: true } : false  );
313
314		document.addEventListener( 'touchmove', function ( e ) {
315			if ( touchmoveCountTimer ) {
316				clearTimeout( touchmoveCountTimer );
317			}
318
319			touchmoveCountTimer = setTimeout( function () {
320				touchmoveCount++;
321			}, 500 );
322		}, supportsPassive ? { passive: true } : false );
323
324		document.addEventListener( 'touchstart', function ( e ) {
325			lastTouchStart = ( new Date() ).getTime();
326		}, supportsPassive ? { passive: true } : false );
327
328		document.addEventListener( 'touchend', function ( e ) {
329			if ( ! lastTouchStart ) {
330				// If the touchstart happened before this script was loaded, but the touchend happened after...
331				return;
332			}
333
334			var now = ( new Date() ).getTime();
335
336			var touchEvent = [];
337			touchEvent.push( now - lastTouchStart );
338
339			if ( lastTouchEnd ) {
340				touchEvent.push( lastTouchStart - lastTouchEnd );
341			}
342
343			touchEvents.push( touchEvent );
344
345			lastTouchEnd = now;
346
347			// Don't record this time as an interval between keypresses.
348			lastKeydown = null;
349			lastKeyup = null;
350			keydowns = {};
351		}, supportsPassive ? { passive: true } : false );
352
353		document.addEventListener( 'scroll', function ( e ) {
354			if ( scrollCountTimer ) {
355				clearTimeout( scrollCountTimer );
356			}
357
358			scrollCountTimer = setTimeout( function () {
359				scrollCount++;
360			}, 500 );
361		}, supportsPassive ? { passive: true } : false );
362	}
363
364	/**
365	 * For the timing/coordinate data that is collected, don't send more than `limit` data points in the request.
366	 * Choose a random slice and send those, with each batch separated by semicolons and the items in each batch
367	 * separated by commas.
368	 */
369	function prepare_array_for_request( a, limit ) {
370		if ( ! limit ) {
371			limit = 100;
372		}
373
374		var rv = '';
375
376		if ( a.length > 0 ) {
377			var random_starting_point = Math.max( 0, Math.floor( Math.random() * a.length - limit ) );
378
379			for ( var i = 0; i < limit && i < a.length; i++ ) {
380				var entry = a[ random_starting_point + i ];
381				rv += entry.join( ',' ) + ';';
382			}
383		}
384
385		return rv;
386	}
387
388	if ( document.readyState !== 'loading' ) {
389		init();
390	} else {
391		document.addEventListener( 'DOMContentLoaded', init );
392	}
393})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.