1*eb872c2aStomLin1998567/** 2*eb872c2aStomLin1998567 * PASSWD Plugin — unlock password-protected sections with captcha verification. 3*eb872c2aStomLin1998567 * 4*eb872c2aStomLin1998567 * On page load, each .passwd_block fetches a fresh captcha via AJAX. 5*eb872c2aStomLin1998567 * The user enters a password and solves the captcha, then submits the form. 6*eb872c2aStomLin1998567 * If both are correct the protected content is revealed inline; 7*eb872c2aStomLin1998567 * otherwise a new captcha is returned automatically. 8*eb872c2aStomLin1998567 */ 9*eb872c2aStomLin1998567 10*eb872c2aStomLin1998567/** 11*eb872c2aStomLin1998567 * Toggle password visibility for a PASSWD input field. 12*eb872c2aStomLin1998567 */ 13*eb872c2aStomLin1998567function passwd_toggle(btn) { 14*eb872c2aStomLin1998567 var wrapper = btn.parentNode; 15*eb872c2aStomLin1998567 var input = wrapper.querySelector('.passwd_input'); 16*eb872c2aStomLin1998567 if (input.type === 'password') { 17*eb872c2aStomLin1998567 input.type = 'text'; 18*eb872c2aStomLin1998567 btn.textContent = ''; 19*eb872c2aStomLin1998567 btn.title = 'Hide password'; 20*eb872c2aStomLin1998567 } else { 21*eb872c2aStomLin1998567 input.type = 'password'; 22*eb872c2aStomLin1998567 btn.textContent = ''; 23*eb872c2aStomLin1998567 btn.title = 'Show password'; 24*eb872c2aStomLin1998567 } 25*eb872c2aStomLin1998567} 26*eb872c2aStomLin1998567 27*eb872c2aStomLin1998567/** 28*eb872c2aStomLin1998567 * Attempt to unlock a PASSWD block identified by its numeric index. 29*eb872c2aStomLin1998567 * 30*eb872c2aStomLin1998567 * @param {number} idx The data-idx attribute of the target block. 31*eb872c2aStomLin1998567 */ 32*eb872c2aStomLin1998567function passwd_unlock(idx) { 33*eb872c2aStomLin1998567 var $block = jQuery('.passwd_block[data-idx="' + idx + '"]'); 34*eb872c2aStomLin1998567 var $form = $block.find('.passwd_form'); 35*eb872c2aStomLin1998567 var data = $form.serializeArray(); 36*eb872c2aStomLin1998567 data.push({name: 'call', value: 'passwd_check'}); 37*eb872c2aStomLin1998567 data.push({name: 'block', value: idx}); 38*eb872c2aStomLin1998567 if (typeof JSINFO !== 'undefined') { 39*eb872c2aStomLin1998567 data.push({name: 'id', value: JSINFO.id}); 40*eb872c2aStomLin1998567 } 41*eb872c2aStomLin1998567 42*eb872c2aStomLin1998567 jQuery.post( 43*eb872c2aStomLin1998567 DOKU_BASE + 'lib/exe/ajax.php', 44*eb872c2aStomLin1998567 data, 45*eb872c2aStomLin1998567 function(resp) { 46*eb872c2aStomLin1998567 if (resp.indexOf('CAPTCHA_FAILED|') === 0) { 47*eb872c2aStomLin1998567 // Reset to the default error text (from config) and show 48*eb872c2aStomLin1998567 $block.find('.passwd_error').show(); 49*eb872c2aStomLin1998567 $block.find('.passwd_captcha') 50*eb872c2aStomLin1998567 .html(resp.substring('CAPTCHA_FAILED|'.length)); 51*eb872c2aStomLin1998567 } else if (resp.indexOf('WRONG_PASSWORD|') === 0) { 52*eb872c2aStomLin1998567 $block.find('.passwd_error').show(); 53*eb872c2aStomLin1998567 $block.find('.passwd_captcha') 54*eb872c2aStomLin1998567 .html(resp.substring('WRONG_PASSWORD|'.length)); 55*eb872c2aStomLin1998567 } else if (resp === 'BLOCK_NOT_FOUND' || resp === 'PASSWORD_NOT_FOUND') { 56*eb872c2aStomLin1998567 $block.find('.passwd_error').text('System error, contact admin').show(); 57*eb872c2aStomLin1998567 } else { 58*eb872c2aStomLin1998567 // Success — show decrypted content, hide the form 59*eb872c2aStomLin1998567 $block.find('.passwd_form').hide(); 60*eb872c2aStomLin1998567 $block.find('.passwd_content').html(resp).show(); 61*eb872c2aStomLin1998567 } 62*eb872c2aStomLin1998567 } 63*eb872c2aStomLin1998567 ); 64*eb872c2aStomLin1998567} 65*eb872c2aStomLin1998567 66*eb872c2aStomLin1998567// On DOM ready: fetch a captcha for every passwd block and bind form submission. 67*eb872c2aStomLin1998567jQuery(function() { 68*eb872c2aStomLin1998567 // Fetch a fresh captcha for each block, so cached pages never show stale tokens. 69*eb872c2aStomLin1998567 jQuery('.passwd_block').each(function() { 70*eb872c2aStomLin1998567 var $block = jQuery(this); 71*eb872c2aStomLin1998567 jQuery.get(DOKU_BASE + 'lib/exe/ajax.php', { 72*eb872c2aStomLin1998567 call: 'passwd_refresh_captcha' 73*eb872c2aStomLin1998567 }, function(html) { 74*eb872c2aStomLin1998567 $block.find('.passwd_captcha').html(html); 75*eb872c2aStomLin1998567 }); 76*eb872c2aStomLin1998567 }); 77*eb872c2aStomLin1998567 78*eb872c2aStomLin1998567 // Intercept form submission to use AJAX instead of a full page reload. 79*eb872c2aStomLin1998567 jQuery(document).on('submit', '.passwd_block .passwd_form', function(e) { 80*eb872c2aStomLin1998567 e.preventDefault(); 81*eb872c2aStomLin1998567 var idx = jQuery(this).closest('.passwd_block').data('idx'); 82*eb872c2aStomLin1998567 passwd_unlock(idx); 83*eb872c2aStomLin1998567 }); 84*eb872c2aStomLin1998567}); 85