From cd68ba1443cf19563b4e2df477b82559697ba762 Mon Sep 17 00:00:00 2001 From: ccd0 Date: Mon, 5 Jul 2021 13:18:50 -0700 Subject: [PATCH] Preliminary support for new first-party captcha on 4chan. --- src/Posting/Captcha.t.coffee | 58 ++++++++++++++++++++++++++++++++++++ src/Posting/QR.coffee | 32 ++++++++++++-------- src/Posting/QR.post.coffee | 3 +- 3 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 src/Posting/Captcha.t.coffee diff --git a/src/Posting/Captcha.t.coffee b/src/Posting/Captcha.t.coffee new file mode 100644 index 000000000..cb22951c2 --- /dev/null +++ b/src/Posting/Captcha.t.coffee @@ -0,0 +1,58 @@ +Captcha.t = + init: -> + return if d.cookie.indexOf('pass_enabled=1') >= 0 + return if not (@isEnabled = !!$('#t-root') or !$.id('postForm')) + + root = $.el 'div', className: 'captcha-root' + @nodes = {root} + + $.addClass QR.nodes.el, 'has-captcha', 'captcha-t' + $.after QR.nodes.com.parentNode, root + + moreNeeded: -> + return + + setup: (focus) -> + return unless @isEnabled + + if !@nodes.container + @nodes.container = $.el 'div', className: 'captcha-container' + $.prepend @nodes.root, @nodes.container + boardID = g.BOARD.ID + threadID = '' + QR.posts[0].thread + $.global -> + el = document.querySelector '#qr .captcha-container' + window.TCaptcha.init el, @boardID, +@threadID + window.TCaptcha.setErrorCb (err) -> + window.dispatchEvent new CustomEvent('CreateNotification', {detail: { + type: 'warning', + content: '' + err + }}) + , {boardID, threadID} + + if focus + $('#t-resp').focus() + + destroy: -> + return unless @isEnabled and @nodes.container + $.global -> + window.TCaptcha.destroy() + $.rm @nodes.container + delete @nodes.container + + getOne: -> + response = {} + if @nodes.container + for key in ['t-response', 't-challenge'] + response[key] = $("[name='#{key}']", @nodes.container).value + if !response['t-response'] + response = null + response + + setUsed: -> + if @nodes.container + $.global -> + window.TCaptcha.clearChallenge() + + occupied: -> + !!@nodes.container diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index fa50ceee0..0b5ee1c0d 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -26,8 +26,6 @@ QR = @posts = [] - @captcha = Captcha.v2 - $.on d, '4chanXInitFinished', -> BoardConfig.ready QR.initReady Callbacks.Post.push @@ -50,6 +48,8 @@ QR = Header.addShortcut 'qr', sc, 540 initReady: -> + captchaVersion = if $('#t-root') then 't' else 'v2' + QR.captcha = Captcha[captchaVersion] QR.postingIsEnabled = true {config} = g.BOARD @@ -684,8 +684,10 @@ QR = if g.BOARD.ID is 'r9k' and !post.com?.match(/[a-z-]/i) err or= 'Original comment required.' - if QR.captcha.isEnabled and !(/\b_ct=/.test(d.cookie) and threadID) and !(err and !force) - captcha = QR.captcha.getOne(!!threadID) or Captcha.cache.request(!!threadID) + if QR.captcha.isEnabled and !(QR.captcha is Captcha.v2 and /\b_ct=/.test(d.cookie) and threadID) and !(err and !force) + captcha = QR.captcha.getOne(!!threadID) + if QR.captcha is Captcha.v2 + captcha or= Captcha.cache.request(!!threadID) unless captcha err = 'No valid captcha.' QR.captcha.setup(!QR.cooldown.auto or d.activeElement is QR.nodes.status) @@ -736,11 +738,15 @@ QR = cb = (response) -> if response? QR.currentCaptcha = response - if response.challenge? - options.form.append 'recaptcha_challenge_field', response.challenge - options.form.append 'recaptcha_response_field', response.response + if QR.captcha is Captcha.v2 + if response.challenge? + options.form.append 'recaptcha_challenge_field', response.challenge + options.form.append 'recaptcha_response_field', response.response + else + options.form.append 'g-recaptcha-response', response.response else - options.form.append 'g-recaptcha-response', response.response + for key, val of response + options.form.append key, val QR.req = $.ajax "https://sys.#{location.hostname.split('.')[1]}.org/#{g.BOARD}/post", options QR.req.progress = '...' @@ -749,10 +755,11 @@ QR = QR.req = progress: '...' abort: -> - Captcha.cache.abort() + if QR.captcha is Captcha.v2 + Captcha.cache.abort() cb = null captcha (response) -> - if Captcha.cache.haveCookie() + if QR.captcha is Captcha.v2 and Captcha.cache.haveCookie() cb?() Captcha.cache.save response if response else if response @@ -780,10 +787,11 @@ QR = $('a', err)?.target = '_blank' # duplicate image link else if (connErr = (!@response or @response.title isnt 'Post successful!')) err = QR.connectionError() - Captcha.cache.save QR.currentCaptcha if QR.currentCaptcha + Captcha.cache.save QR.currentCaptcha if QR.captcha is Captcha.v2 and QR.currentCaptcha else if @status isnt 200 err = "Error #{@statusText} (#{@status})" + QR.captcha.setUsed?() unless connErr delete QR.currentCaptcha if err @@ -901,7 +909,7 @@ QR = if (oldReq = QR.req) and !QR.req.isUploadFinished delete QR.req oldReq.abort() - Captcha.cache.save QR.currentCaptcha if QR.currentCaptcha + Captcha.cache.save QR.currentCaptcha if QR.captcha is Captcha.v2 and QR.currentCaptcha delete QR.currentCaptcha QR.posts[0].unlock() QR.cooldown.auto = false diff --git a/src/Posting/QR.post.coffee b/src/Posting/QR.post.coffee index c0b376be2..304a9e2c8 100644 --- a/src/Posting/QR.post.coffee +++ b/src/Posting/QR.post.coffee @@ -167,7 +167,8 @@ QR.post = class QR.characterCount() @nodes.span.textContent = @com QR.captcha.moreNeeded() - Captcha.cache.prerequest() + if QR.captcha is Captcha.v2 + Captcha.cache.prerequest() isOnlyQuotes: -> (@com or '').trim() is (@quotedText or '').trim()