From 393eb3ec2289293dd4d4caaef17db33bb695fa30 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Sun, 30 Mar 2014 16:53:08 -0700 Subject: [PATCH 1/4] Lets pretend we're smarter than we really are! --- LICENSE | 2 +- builds/4chan-X.user.js | 8 ++++---- builds/crx/script.js | 8 ++++---- src/Miscellaneous/Time.coffee | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/LICENSE b/LICENSE index 5d11769f7..d59212551 100755 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.4.1 - 2014-03-27 +* 4chan X - Version 1.4.1 - 2014-03-30 * * Licensed under the MIT license. * https://github.com/Spittie/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 159521d67..2e88dfa75 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -24,7 +24,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.4.1 - 2014-03-27 +* 4chan X - Version 1.4.1 - 2014-03-30 * * Licensed under the MIT license. * https://github.com/Spittie/4chan-x/blob/master/LICENSE @@ -12408,18 +12408,18 @@ if (this.isClone) { return; } - return this.nodes.date.textContent = Time.funk(Time, this.info.date); + return this.nodes.date.textContent = Time.funk(this.info.date); }, createFunc: function(format) { var code; code = format.replace(/%([A-Za-z])/g, function(s, c) { if (c in Time.formatters) { - return "' + Time.formatters." + c + ".call(date) + '"; + return "' + this.formatters." + c + ".call(date) + '"; } else { return s; } }); - return Function('Time', 'date', "return '" + code + "'"); + return Function('date', "return '" + code + "'"); }, day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], diff --git a/builds/crx/script.js b/builds/crx/script.js index cf9420347..9ad18c9e4 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.4.1 - 2014-03-27 +* 4chan X - Version 1.4.1 - 2014-03-30 * * Licensed under the MIT license. * https://github.com/Spittie/4chan-x/blob/master/LICENSE @@ -12424,18 +12424,18 @@ if (this.isClone) { return; } - return this.nodes.date.textContent = Time.funk(Time, this.info.date); + return this.nodes.date.textContent = Time.funk(this.info.date); }, createFunc: function(format) { var code; code = format.replace(/%([A-Za-z])/g, function(s, c) { if (c in Time.formatters) { - return "' + Time.formatters." + c + ".call(date) + '"; + return "' + this.formatters." + c + ".call(date) + '"; } else { return s; } }); - return Function('Time', 'date', "return '" + code + "'"); + return Function('date', "return '" + code + "'"); }, day: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], diff --git a/src/Miscellaneous/Time.coffee b/src/Miscellaneous/Time.coffee index 0d290cc63..0f08befa2 100755 --- a/src/Miscellaneous/Time.coffee +++ b/src/Miscellaneous/Time.coffee @@ -8,14 +8,14 @@ Time = cb: @node node: -> return if @isClone - @nodes.date.textContent = Time.funk Time, @info.date + @nodes.date.textContent = Time.funk @info.date createFunc: (format) -> code = format.replace /%([A-Za-z])/g, (s, c) -> if c of Time.formatters - "' + Time.formatters.#{c}.call(date) + '" + "' + this.formatters.#{c}.call(date) + '" else s - Function 'Time', 'date', "return '#{code}'" + Function 'date', "return '#{code}'" day: [ 'Sunday' 'Monday' From bbc8899cf19e6fc63a72e3b826f5c143500c5a6b Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Sun, 30 Mar 2014 18:24:42 -0700 Subject: [PATCH 2/4] Lets just build that so that we don't have to do so many logic checks --- builds/4chan-X.user.js | 15 ++++----------- builds/crx/script.js | 15 ++++----------- src/Linkification/Linkify.coffee | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 26 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 2e88dfa75..8e58d25f6 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -8494,6 +8494,9 @@ if (Conf['Comment Expansion']) { ExpandComment.callbacks.push(this.node); } + if (Conf['Embedding'] || Conf['Link Title']) { + this.embedProcess = Function('link', "var data = this.services(link); if (data) { " + ((Conf['Embedding'] ? 'this.embed(data);\n' : '') + (Conf['Title Link'] ? 'this.title(data);' : '')) + " }"); + } return Post.callbacks.push({ name: 'Linkify', cb: this.node @@ -8563,17 +8566,7 @@ Linkify.embedProcess(Linkify.makeLink(link, this)); } }, - embedProcess: function(link) { - var data; - if (data = Linkify.services(link)) { - if (Conf['Embedding']) { - Linkify.embed(data); - } - if (Conf['Link Title']) { - return Linkify.title(data); - } - } - }, + embedProcess: function() {}, regString: /((https?|mailto|git|magnet|ftp|irc):([a-z\d%\/])|[-a-z\d]+[.](aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2})([:\/]|(?!.))|[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}|[-\w\d.@]+@[a-z\d.-]+\.[a-z\d])/i, makeRange: function(startNode, endNode, startOffset, endOffset) { var range; diff --git a/builds/crx/script.js b/builds/crx/script.js index 9ad18c9e4..ed5b198c7 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -8511,6 +8511,9 @@ if (Conf['Comment Expansion']) { ExpandComment.callbacks.push(this.node); } + if (Conf['Embedding'] || Conf['Link Title']) { + this.embedProcess = Function('link', "var data = this.services(link); if (data) { " + ((Conf['Embedding'] ? 'this.embed(data);\n' : '') + (Conf['Title Link'] ? 'this.title(data);' : '')) + " }"); + } return Post.callbacks.push({ name: 'Linkify', cb: this.node @@ -8580,17 +8583,7 @@ Linkify.embedProcess(Linkify.makeLink(link, this)); } }, - embedProcess: function(link) { - var data; - if (data = Linkify.services(link)) { - if (Conf['Embedding']) { - Linkify.embed(data); - } - if (Conf['Link Title']) { - return Linkify.title(data); - } - } - }, + embedProcess: function() {}, regString: /((https?|mailto|git|magnet|ftp|irc):([a-z\d%\/])|[-a-z\d]+[.](aero|asia|biz|cat|com|coop|info|int|jobs|mobi|museum|name|net|org|post|pro|tel|travel|xxx|edu|gov|mil|[a-z]{2})([:\/]|(?!.))|[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}\.[\d]{1,3}|[-\w\d.@]+@[a-z\d.-]+\.[a-z\d])/i, makeRange: function(startNode, endNode, startOffset, endOffset) { var range; diff --git a/src/Linkification/Linkify.coffee b/src/Linkification/Linkify.coffee index 3b92d062f..95cd2f03a 100755 --- a/src/Linkification/Linkify.coffee +++ b/src/Linkification/Linkify.coffee @@ -5,6 +5,17 @@ Linkify = if Conf['Comment Expansion'] ExpandComment.callbacks.push @node + if Conf['Embedding'] or Conf['Link Title'] + @embedProcess = Function 'link', + "var data = this.services(link); + if (data) { + #{ + (if Conf['Embedding'] then 'this.embed(data);\n' else '') + + if Conf['Title Link'] then 'this.title(data);' else '' + } + } + " + Post.callbacks.push name: 'Linkify' cb: @node @@ -63,10 +74,7 @@ Linkify = Linkify.embedProcess Linkify.makeLink link, @ return - embedProcess: (link) -> - if data = Linkify.services link - Linkify.embed data if Conf['Embedding'] - Linkify.title data if Conf['Link Title'] + embedProcess: -> return regString: ///( # http, magnet, ftp, etc From 7bc7aed9984a87fc17b7007b74cb90f96a02c58a Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 3 Apr 2014 01:47:21 +0200 Subject: [PATCH 3/4] Fix captchas, again. #1531 --- CHANGELOG.md | 4 ++ src/Posting/QR.captcha.coffee | 83 ++++++++--------------------------- src/Posting/QR.coffee | 31 +++---------- src/Posting/QR.post.coffee | 2 + 4 files changed, 31 insertions(+), 89 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 701db7cd7..b6fff3bc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +- Fix captcha submission:
+ Captchas were reloaded the instant a post was submitted to 4chan. Unfortunately, a recent change to reCAPTCHA made it so reloading captchas invalidates the ones that loaded but not yet used. This is now fixed by only unloading the captcha, and only load new ones after the post is submitted.
+ This also kills captcha caching, so the feature was removed. + ### 3.19.4 - *2014-03-27* - Fix captcha not refreshing. diff --git a/src/Posting/QR.captcha.coffee b/src/Posting/QR.captcha.coffee index 4c65c8d2c..8ecd95300 100644 --- a/src/Posting/QR.captcha.coffee +++ b/src/Posting/QR.captcha.coffee @@ -1,26 +1,21 @@ QR.captcha = init: -> return if d.cookie.indexOf('pass_enabled=1') >= 0 - container = $.id 'captchaContainer' - return unless @isEnabled = !!container + return unless @isEnabled = !!$.id 'captchaContainer' imgContainer = $.el 'div', 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 @nodes = img: imgContainer.firstChild input: input - $.on input, 'focus', @setup - <% if (type === 'userscript') { %> # XXX Firefox lacks focusin/focusout support. $.on input, 'blur', QR.focusout @@ -30,9 +25,16 @@ QR.captcha = $.addClass QR.nodes.el, 'has-captcha' $.after QR.nodes.com.parentNode, [imgContainer, input] - @setupObserver = new MutationObserver @afterSetup - @setupObserver.observe container, childList: true + @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 setup: -> $.globalEval 'loadRecaptcha()' afterSetup: -> @@ -40,82 +42,37 @@ 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 - $.off input, 'focus', QR.captcha.setup + 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() - sync: (captchas) -> - QR.captcha.captchas = captchas - QR.captcha.count() + destroy: -> + $.globalEval 'Recaptcha.destroy()' + @beforeSetup() getOne: -> - @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() + challenge = @nodes.img.alt + response = @nodes.input.value.trim() + if response and !/\s/.test response # one-word-captcha: # If there's only one word, duplicate it. - response = "#{response} #{response}" unless /\s/.test response + response = "#{response} #{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 # not loaded yet. - 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")' @@ -124,8 +81,6 @@ 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 70b357fef..0d4a9673d 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -478,6 +478,9 @@ QR = # 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() @@ -511,6 +514,7 @@ QR = {req} = QR delete QR.req + QR.captcha.destroy() if QR.captcha.isEnabled post = QR.posts[0] post.unlock() @@ -540,23 +544,12 @@ QR = # Remove the obnoxious 4chan Pass ad. if /mistyped/i.test err.textContent err = 'You seem to have mistyped the CAPTCHA.' - # 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 + QR.cooldown.auto = 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 = if QR.captcha.isEnabled - !!QR.captcha.captchas.length - else - true + QR.cooldown.auto = !QR.captcha.isEnabled QR.cooldown.set delay: m[1] else # stop auto-posting QR.cooldown.auto = false @@ -592,18 +585,6 @@ 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 275406e7e..8d04f2de1 100644 --- a/src/Posting/QR.post.coffee +++ b/src/Posting/QR.post.coffee @@ -89,6 +89,8 @@ QR.post = class for name in ['thread', 'name', 'email', 'sub', 'com', 'fileButton', 'filename', 'spoiler', 'flag'] continue unless 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 From a4bd81de54850f90e91a906268996c42d7a81632 Mon Sep 17 00:00:00 2001 From: Mayhem Date: Thu, 3 Apr 2014 01:47:47 +0200 Subject: [PATCH 4/4] Release 4chan X v3.19.5. --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6fff3bc1..898c937b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +### 3.19.5 - *2014-04-03* + - Fix captcha submission:
Captchas were reloaded the instant a post was submitted to 4chan. Unfortunately, a recent change to reCAPTCHA made it so reloading captchas invalidates the ones that loaded but not yet used. This is now fixed by only unloading the captcha, and only load new ones after the post is submitted.
This also kills captcha caching, so the feature was removed. diff --git a/package.json b/package.json index a5714ff52..e74731b7c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "4chan-X", - "version": "3.19.4", + "version": "3.19.5", "description": "Cross-browser extension for productive lurking on 4chan.", "meta": { "name": "4chan X",