PageSourceSearch

https://darwin-eu.org/media/plg_captcha_securimage/js/securimage.js?a3ae15

js darwin-eu.org collected 2026-10-02 05:58:48 UTC 12,142 bytes, 420 lines download raw bytes

1
2
3
4/*!
5 * Securimage CAPTCHA Audio Library
6 * https://www.phpcaptcha.org/
7 *
8 * Copyright 2015 phpcaptcha.org
9 * Released under the BSD-3 license
10 * See https://github.com/dapphp/securimage/blob/master/README.md
11 */
12
13var SecurimageAudio = function (options) {
14	this.html5Support = true;
15	this.flashFallback = false;
16	this.captchaId = null;
17	this.playing = false;
18	this.reload = false;
19	this.audioElement = null;
20	this.controlsElement = null;
21	this.playButton = null;
22	this.playButtonImage = null;
23	this.loadingImage = null;
24
25	if (options.audioElement) {
26		this.audioElement = document.getElementById(options.audioElement);
27	}
28	if (options.controlsElement) {
29		this.controlsElement = document.getElementById(options.controlsElement);
30	}
31
32	this.init();
33}
34
35SecurimageAudio.prototype.init = function () {
36	var ua = navigator.userAgent.toLowerCase();
37	var ieVer = (ua.indexOf('msie') != -1) ? parseInt(ua.split('msie')[1]) : false;
38	// ie 11+ detection
39	if (!ieVer && null != (ieVer = ua.match(/trident\/.*rv:(\d+\.\d+)/)))
40		ieVer = parseInt(ieVer[1]);
41
42	var objAu = this.audioElement.getElementsByTagName('object');
43	if (objAu.length > 0) {
44		objAu = objAu[0];
45	} else {
46		objAu = null;
47	}
48
49	if (ieVer) {
50		if (ieVer < 9) {
51			// no html5 audio support, hide player controls
52			this.controlsElement.style.display = 'none';
53			this.html5Support = false;
54			return;
55		} else if ('' == this.audioElement.canPlayType('audio/wav')) {
56			// check for mpeg <source> tag - if not found then fallback to flash
57			var sources = this.audioElement.getElementsByTagName('source');
58			var mp3support = false;
59			var type;
60
61			if (objAu) {
62				this.flashFallback = true;
63			}
64
65			for (var i = 0; i < sources.length; ++i) {
66				type = sources[i].attributes["type"].value;
67				if (type.toLowerCase().indexOf('mpeg') >= 0 || type.toLowerCase().indexOf('mp3') >= 0) {
68					mp3support = true;
69					break;
70				}
71			}
72
73			if (false == mp3support) {
74				// browser supports <audio> but does not support WAV audio and no flash audio available
75				this.html5Support = false;
76
77				if (this.flashFallback) {
78					// ie9+? bug - flash object does not display when moved from within audio tag to other dom node
79					var newObjAu = document.createElement('object');
80					var newParams = document.createElement('param');
81					var oldParams = objAu.getElementsByTagName('param');
82					this.copyElementAttributes(newObjAu, objAu);
83					if (oldParams.length > 0) {
84						this.copyElementAttributes(newParams, oldParams[0]);
85						newObjAu.appendChild(newParams);
86					}
87					objAu.parentNode.removeChild(objAu);
88					this.audioElement.parentNode.appendChild(newObjAu);
89				}
90
91				this.audioElement.parentNode.removeChild(this.audioElement);
92				this.controlsElement.parentNode.removeChild(this.controlsElement);
93
94				return;
95			}
96		}
97	}
98
99	this.audioElement.addEventListener('playing', this.updateControls.bind(this), false);
100	this.audioElement.addEventListener('ended', this.audioStopped.bind(this), false);
101
102	// find the element used as the play button and register click event to play/stop audio
103	var children = this.controlsElement.getElementsByTagName('*');
104	for (var i = 0; i < children.length; ++i) {
105		var el = children[i];
106		if (undefined != el.className && (typeof el.className === 'string' || el.className instanceof String)) {
107			if (el.className.indexOf('play_button') >= 0) {
108				this.playButton = el;
109				el.addEventListener('click', this.play.bind(this), false);
110			} else if (el.className.indexOf('$audioObj_image') >= 0) {
111				this.playButtonImage = el;
112			} else if (el.className.indexOf('loading_image') >= 0) {
113				this.loadingImage = el;
114			}
115		}
116	}
117
118	if (objAu) {
119		// remove flash object from DOM
120		objAu.parentNode.removeChild(objAu);
121	}
122}
123
124SecurimageAudio.prototype.play = function (evt) {
125	if (null != this.playButton) {
126		this.playButton.blur();
127	}
128
129	if (this.reload) {
130		this.replaceElements();
131		this.reload = false;
132	}
133
134	try {
135		if (!this.playing) {
136			if (this.playButtonImage != null) {
137				this.playButtonImage.style.display = 'none';
138			}
139			if (this.loadingImage != null) {
140				this.loadingImage.style.display = '';
141			}
142			//TODO: FIX, most likely browser doesn't support audio type
143			this.audioElement.onerror = this.audioError;
144			this.audioElement.dataset.played = true;
145			try {
146				this.audioElement.play();
147			} catch (ex) {
148				alert('Audio error: ' + ex);
149			}
150		} else {
151			this.audioElement.pause();
152			if (this.loadingImage != null) {
153				this.loadingImage.style.display = 'none';
154			}
155			if (this.playButtonImage != null) {
156				this.playButtonImage.style.display = '';
157			}
158			this.playing = false;
159		}
160	} catch (ex) {
161		alert('Audio error: ' + ex);
162	}
163
164	if (undefined !== evt) {
165		evt.preventDefault();
166	}
167	return false;
168}
169
170SecurimageAudio.prototype.refresh = function (captchaId) {
171	if (!this.html5Support) {
172		return;
173	}
174
175	if (undefined !== captchaId) {
176		this.captchaId = captchaId;
177	}
178
179	this.playing = true;
180	this.reload = false;
181	this.play(); // stops audio if playing
182	this.reload = true;
183
184	if (this.audioElement.dataset.played != undefined) {
185
186		console.log(this.audioElement.dataset.played);
187		setTimeout(() => {
188			this.play();
189			this.reload = false;
190		}, 1000);
191	}
192
193	return false;
194}
195
196SecurimageAudio.prototype.copyElementAttributes = function (newEl, el) {
197	for (var i = 0, atts = el.attributes, n = atts.length; i < n; ++i) {
198		newEl.setAttribute(atts[i].nodeName, atts[i].value);
199	}
200
201	return newEl;
202}
203
204SecurimageAudio.prototype.replaceElements = function () {
205	var parent = this.audioElement.parentNode;
206	parent.removeChild(this.audioElement);
207
208	var newAudioEl = document.createElement('audio');
209
210	for (var c = 0; c < this.audioElement.children.length; ++c) {
211		if (this.audioElement.children[c].tagName.toLowerCase() != 'source') continue;
212		var sourceEl = document.createElement('source');
213		this.copyElementAttributes(sourceEl, this.audioElement.children[c]);
214		var cid = (null !== this.captchaId) ? this.captchaId : (Math.random() + '').replace('0.', '');
215		sourceEl.src = sourceEl.src.replace(/id=[a-zA-Z0-9]+/, 'id=' + cid);
216		newAudioEl.appendChild(sourceEl);
217	}
218
219	this.audioElement = null;
220	this.audioElement = newAudioEl;
221	parent.appendChild(this.audioElement);
222
223	this.audioElement.addEventListener('playing', this.updateControls.bind(this), false);
224	this.audioElement.addEventListener('ended', this.audioStopped.bind(this), false);
225
226	if (null != this.playButton) {
227		this.playButton.blur();
228		this.playButton.href = this.playButton.href + Math.random();
229	}
230}
231
232SecurimageAudio.prototype.updateControls = function () {
233	this.playing = true;
234	if (this.loadingImage != null) {
235		this.loadingImage.style.display = 'none';
236	}
237	if (this.playButtonImage != null) {
238		this.playButtonImage.style.display = '';
239	}
240}
241
242SecurimageAudio.prototype.audioStopped = function () {
243	this.playing = false;
244}
245
246SecurimageAudio.prototype.audioError = function (err) {
247	alert('Audio playback error: ' + err.message);
248}
249
250
251
252function updateSICatpcha(captchaImage) {
253	if (captchaImage) {
254		var captchaImage = document.getElementById(captchaImage);
255		captchaImage.src = captchaImage.getAttribute('data-url') + '&amp;' + Math.random();
256
257		var captchaText = document.getElementById(captchaImage.getAttribute('data-text-input'));
258		if (captchaText) {
259			captchaText.value = '';
260			// @todo: Implement focus() only when captcha was the only error with the form
261			// captchaText.focus();
262		}
263		var captchaAudio = captchaImage.getAttribute('data-audioObj');
264		if (captchaAudio && typeof window[captchaAudio] !== 'undefined') {
265			window[captchaAudio].refresh();
266		}
267	}
268};
269
270function updateCaptchas(timeout=1500) {
271	setTimeout( () =>{
272		captchas = document.querySelectorAll('.img-securimage-captcha');
273		let i = 0;
274		captchas.forEach(captcha => {
275			i++;
276			setTimeout(() => {
277				updateSICatpcha(captcha.id)
278			}, 250 * i);
279		});
280	}, timeout);
281};
282
283
284const SecurimageToken = {
285	getToken(el) {
286		const self = this;
287		form = el.closest('form');
288		// Get the form data
289		formData = new FormData(form);
290		formData.delete('view');
291		formData.delete('task');
292		formData.append('component', formData.get('option'));
293		formData.delete('option');
294
295		const msgContainerSelector = self.getSelector(el.parentNode.querySelector('.securimage-msg'));
296		let loader = document.createElement('img');
297		loader.src = 'media/plg_captcha_securimage/images/loading/loading.gif';
298		loader.style = 'width:18px;height:18px';
299		document.querySelector(msgContainerSelector).appendChild(loader);
300		const catpchaContainer = el.closest('.captcha-container').querySelector('.captcha-container');
301		const captchaInput = catpchaContainer.querySelector('.sicaptcha');
302		el.disabled = true;
303		el.setAttribute('data-label', el.innerHTML);
304
305
306		Joomla.request({
307			url: el.getAttribute('data-url') + '&amp;' + Math.random(),
308			method: 'POST',
309			data: new URLSearchParams(formData).toString(),
310			perform: true,
311			onSuccess: function onSuccess(resp) {
312				
313				catpchaContainer.style["display"] = 'none';
314				
315				// Remove loader image
316				loader.parentNode.removeChild(loader);
317				var response = {};
318				try {
319					response = JSON.parse(resp);
320				} catch (e) {
321					Joomla.renderMessages({
322						error: [Joomla.Text._('PLG_CAPTCHA_SECURIMAGE_TOKEN_ERROR_INVALID_RESPONSE')]
323					}, msgContainerSelector, false, 5000);
324
325					return;
326				}
327
328				if (response.success && response.data && response.data.length > 0) {
329					// Display all messages that we got
330					response.data.forEach(function (value) {
331						if (value === null) {
332							Joomla.renderMessages({
333								error: ['NULL Ajax response']
334							}, msgContainerSelector, false, 7000);
335							return;
336						}
337
338						// Display success alert
339						if (value.success) {
340							catpchaContainer.style["display"] = 'none';
341							let timeleft = 60;
342							var tokenTimer = setInterval(function () {
343								if (timeleft <= 0) {
344									clearInterval(tokenTimer);
345									el.innerHTML = el.getAttribute('data-label');
346									catpchaContainer.style["display"] = '';
347									el.disabled = false;
348								} else {
349									el.innerHTML = Joomla.Text._('PLG_CAPTCHA_SECURIMAGE_TOKEN_WAIT_FOR_NEW_TOKEN').replace('[time]', timeleft);
350								}
351								timeleft -= 1;
352							}, 1000);
353
354							captchaInput.removeAttribute('data-required', 'required');
355							captchaInput.classList.remove("required", "required-field", "validate-sicaptcha", "ce-validation-error");
356
357							Joomla.renderMessages({
358								message: [value.message]
359							}, msgContainerSelector, true);
360						} else {
361							updateCaptchas();
362							catpchaContainer.style["display"] = '';
363							el.disabled = false;
364							Joomla.renderMessages({
365								error: [value.message]
366							}, msgContainerSelector, false, 7000);
367						}
368					});
369				}
370			},
371			onComplete: function onComplete() {
372				
373			},
374			onError: function onError() {
375				updateCaptchas();
376				catpchaContainer.style["display"] = '';
377				el.disabled = false;
378				Joomla.renderMessages({
379					error: [Joomla.Text._('PLG_CAPTCHA_SECURIMAGE_TOKEN_ERROR_RESPONSE')], msgContainerSelector
380				}, msgContainerSelector, false, 5000);
381			}
382		});
383	},
384	
385	getSelector(elm) {
386		if (elm.tagName === "BODY") return "BODY";
387		const names = [];
388		while (elm.parentElement && elm.tagName !== "BODY") {
389			if (elm.id) {
390				names.unshift("#" + elm.getAttribute("id")); // getAttribute, because `elm.id` could also return a child element with name "id"
391				break; // Because ID should be unique, no more is needed. Remove the break, if you always want a full path.
392			} else {
393				let c = 1, e = elm;
394				for (; e.previousElementSibling; e = e.previousElementSibling, c++);
395				names.unshift(elm.tagName + ":nth-child(" + c + ")");
396			}
397			elm = elm.parentElement;
398		}
399		return names.join(">");
400	},
401	init() {
402		const self = this;
403		tokenBtns = document.querySelectorAll('.btn-captcha-token');
404		tokenBtns.forEach(btn => {
405			btn.addEventListener("click", () => {
406				self.getToken(btn);
407			});
408		});
409	},
410};
411
412
413
414// A delay of a second helps avoid issues
415// and no one is able to fill a form in less than one second,
416// so this is not an issue
417window.onload = () => {
418	SecurimageToken.init();
419	updateCaptchas();
420}

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.