From a122981aa9d8b8d66f7761acef19cd51c86def3e Mon Sep 17 00:00:00 2001 From: ccd0 Date: Sun, 27 Apr 2014 18:28:50 -0700 Subject: [PATCH] Revert "Fix captchas, again. #1531" This reverts commit fd703d42bad855d9e103ecbdb2628fcef94b9651. Conflicts: CHANGELOG.md --- src/Posting/QR.captcha.coffee | 90 +++++++++++++++++++++++++++-------- src/Posting/QR.coffee | 31 +++++++++--- src/Posting/QR.post.coffee | 2 - 3 files changed, 96 insertions(+), 27 deletions(-) diff --git a/src/Posting/QR.captcha.coffee b/src/Posting/QR.captcha.coffee index 31c48f008..029620f1f 100644 --- a/src/Posting/QR.captcha.coffee +++ b/src/Posting/QR.captcha.coffee @@ -1,7 +1,8 @@ QR.captcha = init: -> return if d.cookie.indexOf('pass_enabled=1') >= 0 - return unless @isEnabled = !!$.id 'captchaContainer' + container = $.id 'captchaContainer' + return unless @isEnabled = !!container $.globalEval 'loadRecaptcha()' if Conf['Auto-load captcha'] @@ -9,9 +10,11 @@ QR.captcha = className: 'captcha-img' title: 'Reload reCAPTCHA' innerHTML: '' + hidden: true input = $.el 'input', className: 'captcha-input field' title: 'Verification' + placeholder: 'Focus to load reCAPTCHA' autocomplete: 'off' spellcheck: false tabIndex: 45 @@ -19,22 +22,17 @@ QR.captcha = img: imgContainer.firstChild input: input + $.on input, 'focus', @setup + $.on input, 'blur', QR.focusout $.on input, 'focus', QR.focusin $.addClass QR.nodes.el, 'has-captcha' $.after QR.nodes.com.parentNode, [imgContainer, input] - - @beforeSetup() - @afterSetup() # reCAPTCHA might have loaded before the QR. - beforeSetup: -> - {img, input} = @nodes - img.parentNode.hidden = true - input.value = '' - input.placeholder = 'Focus to load reCAPTCHA' - $.on input, 'focus', @setup + @setupObserver = new MutationObserver @afterSetup - @setupObserver.observe $.id('captchaContainer'), childList: true + @setupObserver.observe container, childList: true + @afterSetup() # reCAPTCHA might have loaded before the QR. setup: -> $.globalEval 'loadRecaptcha()' afterSetup: -> @@ -42,37 +40,89 @@ QR.captcha = QR.captcha.setupObserver.disconnect() delete QR.captcha.setupObserver + setLifetime = (e) -> QR.captcha.lifetime = e.detail + $.on window, 'captcha:timeout', setLifetime + $.globalEval 'window.dispatchEvent(new CustomEvent("captcha:timeout", {detail: RecaptchaState.timeout}))' + $.off window, 'captcha:timeout', setLifetime + {img, input} = QR.captcha.nodes img.parentNode.hidden = false - input.placeholder = 'Verification' $.off input, 'focus', QR.captcha.setup $.on input, 'keydown', QR.captcha.keydown.bind QR.captcha $.on img.parentNode, 'click', QR.captcha.reload.bind QR.captcha + $.get 'captchas', [], ({captchas}) -> + QR.captcha.sync captchas + $.sync 'captchas', QR.captcha.sync + QR.captcha.nodes.challenge = challenge new MutationObserver(QR.captcha.load.bind QR.captcha).observe challenge, childList: true subtree: true attributes: true QR.captcha.load() - destroy: -> - $.globalEval 'Recaptcha.destroy()' - @beforeSetup() + + sync: (captchas) -> + QR.captcha.captchas = captchas + QR.captcha.count() + getOne: -> - challenge = @nodes.img.alt - response = @nodes.input.value.trim() - if response and !/\s/.test response + @clear() + if captcha = @captchas.shift() + {challenge, response} = captcha + @count() + $.set 'captchas', @captchas + else + challenge = @nodes.img.alt + if response = @nodes.input.value then @reload() + if response + response = response.trim() # one-word-captcha: # If there's only one word, duplicate it. - response = "#{response} #{response}" + response = "#{response} #{response}" unless /\s/.test response {challenge, response} + + save: -> + return unless response = @nodes.input.value.trim() + @captchas.push + challenge: @nodes.img.alt + response: response + timeout: @timeout + @count() + @reload() + $.set 'captchas', @captchas + + clear: -> + return unless @captchas.length + now = Date.now() + for captcha, i in @captchas + break if captcha.timeout > now + return unless i + @captchas = @captchas[i..] + @count() + $.set 'captchas', @captchas + load: -> return unless @nodes.challenge.firstChild # -1 minute to give upload some time. + @timeout = Date.now() + @lifetime * $.SECOND - $.MINUTE challenge = @nodes.challenge.firstChild.value @nodes.img.alt = challenge @nodes.img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}" @nodes.input.value = null + @clear() + + count: -> + count = if @captchas then @captchas.length else 0 + @nodes.input.placeholder = switch count + when 0 + 'Verification (Shift + Enter to cache)' + when 1 + 'Verification (1 cached captcha)' + else + "Verification (#{count} cached captchas)" + @nodes.input.alt = count # For XTRM RICE. + reload: (focus) -> # the 't' argument prevents the input from being focused $.globalEval 'Recaptcha.reload("t")' @@ -82,6 +132,8 @@ QR.captcha = keydown: (e) -> if e.keyCode is 8 and not @nodes.input.value @reload() + else if e.keyCode is 13 and e.shiftKey + @save() else return e.preventDefault() diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 241a5cbb4..a16f64f1f 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -668,9 +668,6 @@ QR = onerror: (err, url, line) -> # Connection error, or www.4chan.org/banned delete QR.req - if QR.captcha.isEnabled - QR.captcha.destroy() - QR.captcha.setup() post.unlock() QR.cooldown.auto = false QR.status() @@ -707,7 +704,6 @@ QR = {req} = QR delete QR.req - QR.captcha.destroy() if QR.captcha.isEnabled post = QR.posts[0] post.unlock() @@ -739,12 +735,23 @@ QR = err = 'You seem to have mistyped the CAPTCHA.' else if /expired/i.test err.textContent err = 'This CAPTCHA is no longer valid because it has expired.' - QR.cooldown.auto = false + # Enable auto-post if we have some cached captchas. + QR.cooldown.auto = if QR.captcha.isEnabled + !!QR.captcha.captchas.length + else if err is 'Connection error with sys.4chan.org.' + true + else + # Something must've gone terribly wrong if you get captcha errors without captchas. + # Don't auto-post indefinitely in that case. + false # Too many frequent mistyped captchas will auto-ban you! # On connection error, the post most likely didn't go through. QR.cooldown.set delay: 2 else if err.textContent and m = err.textContent.match /wait\s+(\d+)\s+second/i - QR.cooldown.auto = !QR.captcha.isEnabled + QR.cooldown.auto = if QR.captcha.isEnabled + !!QR.captcha.captchas.length + else + true QR.cooldown.set delay: m[1] else # stop auto-posting QR.cooldown.auto = false @@ -784,6 +791,18 @@ QR = # Enable auto-posting if we have stuff left to post, disable it otherwise. postsCount = QR.posts.length - 1 QR.cooldown.auto = postsCount and isReply + if QR.cooldown.auto and QR.captcha.isEnabled and (captchasCount = QR.captcha.captchas.length) < 3 and captchasCount < postsCount + notif = new Notification 'Quick reply warning', + body: "You are running low on cached captchas. Cache count: #{captchasCount}." + icon: Favicon.logo + notif.onclick = -> + QR.open() + QR.captcha.nodes.input.focus() + window.focus() + notif.onshow = -> + setTimeout -> + notif.close() + , 7 * $.SECOND unless Conf['Persistent QR'] or QR.cooldown.auto QR.close() diff --git a/src/Posting/QR.post.coffee b/src/Posting/QR.post.coffee index c2d530381..25ae0ff11 100644 --- a/src/Posting/QR.post.coffee +++ b/src/Posting/QR.post.coffee @@ -91,8 +91,6 @@ QR.post = class return unless @ is QR.selected for name in ['thread', 'name', 'email', 'sub', 'com', 'fileButton', 'filename', 'spoiler', 'flag'] when node = QR.nodes[name] node.disabled = lock - if QR.captcha.isEnabled - QR.captcha.nodes.input.disabled = lock @nodes.rm.style.visibility = if lock then 'hidden' else '' (if lock then $.off else $.on) QR.nodes.filename.previousElementSibling, 'click', QR.openFileInput @nodes.spoiler.disabled = lock