diff --git a/package.json b/package.json index 87076441e..65f5e932b 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "chromeStoreID": "ohnjgmpcibpbafdlkimncjhflgedgpam", "recaptchaKey": "6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc", "youtubeAPIKey": "AIzaSyB5_zaen_-46Uhz1xGR-lz1YoUMHqCD6CE", + "captchaServiceLinks": [["captcha.guru", "https://captcha.guru/en/regen/?ref=104127"], ["2captcha", "https://2captcha.com?from=7935487"]], "distBranch": "gh-pages", "includes_only": [ "*://boards.4chan.org/*", diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee index 43dad3dc2..dca022b7d 100644 --- a/src/General/Settings.coffee +++ b/src/General/Settings.coffee @@ -555,7 +555,7 @@ Settings = $.id('lastarchivecheck').textContent = 'never' items = {} - for name in ['archiveLists', 'archiveAutoUpdate', 'captchaLanguage', 'boardnav', 'time', 'timeLocale', 'backlink', 'pastedname', 'fileInfo', 'QR.personas', 'favicon', 'usercss', 'customCooldown', 'jsWhitelist'] + for name in ['archiveLists', 'archiveAutoUpdate', 'captchaLanguage', 'captchaServiceDomain', 'boardnav', 'time', 'timeLocale', 'backlink', 'pastedname', 'fileInfo', 'QR.personas', 'favicon', 'usercss', 'customCooldown', 'jsWhitelist'] items[name] = Conf[name] input = inputs[name] event = if name in ['archiveLists', 'archiveAutoUpdate', 'QR.personas', 'favicon', 'usercss'] then 'change' else 'input' @@ -571,6 +571,11 @@ Settings = Settings[key].call input return + $.on inputs['captchaServiceKey'], 'input', Settings.captchaServiceKey + $.get 'captchaServiceKey', Conf['captchaServiceKey'], ({captchaServiceKey}) -> + Conf['captchaServiceKey'] = captchaServiceKey + Settings.captchaServiceDomainList() + interval = inputs['Interval'] customCSS = inputs['Custom CSS'] applyCSS = $ '#apply-css', section @@ -702,6 +707,31 @@ Settings = Conf['selectedArchives'] = selectedArchives Redirect.selectArchives() + captchaServiceDomain: -> + $.get 'captchaServiceKey', Conf['captchaServiceKey'], ({captchaServiceKey}) => + keyInput = $('[name=captchaServiceKey]') + keyInput.value = captchaServiceKey[@value.trim()] or '' + keyInput.disabled = !@value.trim() + + captchaServiceKey: -> + domain = Conf['captchaServiceDomain'] + value = @value.trim() + Conf['captchaServiceKey'][domain] = value + $.get 'captchaServiceKey', Conf['captchaServiceKey'], ({captchaServiceKey}) -> + captchaServiceKey[domain] = value + delete captchaServiceKey[domain] unless value or (domain of Config['captchaServiceKey'][0]) + Conf['captchaServiceKey'] = captchaServiceKey + $.set 'captchaServiceKey', captchaServiceKey + Settings.captchaServiceDomainList() + + captchaServiceDomainList: -> + list = $.id 'list-captchaServiceDomain' + $.rmAll list + for domain of Conf['captchaServiceKey'] + $.add list, $.el 'option', + textContent: domain + return + boardnav: -> Header.generateBoardList @value diff --git a/src/General/Settings/Advanced.html b/src/General/Settings/Advanced.html index 779ac3bd6..2fd445cc2 100644 --- a/src/General/Settings/Advanced.html +++ b/src/General/Settings/Advanced.html @@ -25,6 +25,20 @@
+
+ Captcha Solving Service +
+ Supported services include + <%= meta.captchaServiceLinks.map(function(x) {return '' + x[0] + ''}).join(', ') %>, + and any other service implementing the 2captcha API.
+ Leave blank to disable. +
+ Domain: + API Key: + +
+
+
Custom Board Navigation
diff --git a/src/Posting/Captcha.service.coffee b/src/Posting/Captcha.service.coffee new file mode 100644 index 000000000..97e61daa2 --- /dev/null +++ b/src/Posting/Captcha.service.coffee @@ -0,0 +1,76 @@ +Captcha.service = + init: -> + Conf['captchaServiceDomain'] = '' + $.on d, 'LoadCaptcha', @loadCaptcha.bind(@) + $.on d, 'AbortCaptcha SaveCaptcha', @abortCaptcha.bind(@) + $.on d, 'RequestCaptcha', @requestCaptcha.bind(@) + + isEnabled: -> + Conf['captchaServiceDomain'] and /\S/.test(Conf['captchaServiceDomain']) + + loadCaptcha: (e) -> + return unless @isEnabled() + e.preventDefault() if !@pending or @aborted + + abortCaptcha: -> + @aborted = true if @pending + + requestCaptcha: (e) -> + return unless @isEnabled() + return if e.defaultPrevented + if @pending and @aborted + @aborted = false + return + return if @pending + @pending = true + @aborted = false + e.preventDefault() + key = Conf['captchaServiceKey'][Conf['captchaServiceDomain']] + return @noCaptcha 'API key not set' unless key and /\S/.test(key) + url = "#{Conf['captchaServiceDomain']}/in.php?key=#{encodeURIComponent key}&method=userrecaptcha&googlekey=<%= meta.recaptchaKey %>&pageurl=https://boards.4channel.org/v/" + @req = CrossOrigin.ajax url, + responseType: 'text' + onloadend: => + response = @req.response or '' + parts = response.split('|') + if parts[0] is 'OK' + @requestID = parts[1] + @interval = setInterval @poll.bind(@), 5 * $.SECOND + else + @noCaptcha() + + poll: -> + key = Conf['captchaServiceKey'][Conf['captchaServiceDomain']] + return @noCaptcha 'API key not set' unless key and /\S/.test(key) + url = "#{Conf['captchaServiceDomain']}/res.php?key=#{encodeURIComponent key}&action=get&id=#{encodeURIComponent @requestID}" + @req = CrossOrigin.ajax url, + responseType: 'text' + onloadend: => + return unless @req.status + response = @req.response or '' + parts = response.split('|') + if parts[0] is 'CAPCHA_NOT_READY' + # pass + else if parts[0] is 'OK' + clearInterval @interval + @saveCaptcha parts[1] + else + clearInterval @interval + @noCaptcha() + + noCaptcha: (error) -> + @pending = false + return if @aborted + error = if @req.status is 200 + @req.response + else if @req.status + "#{@req.statusText} (#{@req.status})" + else + 'Connection Error' + error = "Failed to retrieve captcha: #{error}" + $.event 'NoCaptcha', {error} + + saveCaptcha: (response) -> + @pending = false + timeout = Date.now() + Captcha.v2.lifetime + $.event 'SaveCaptcha', {response, timeout} diff --git a/src/config/Config.coffee b/src/config/Config.coffee index 26d84b565..175025dd0 100644 --- a/src/config/Config.coffee +++ b/src/config/Config.coffee @@ -1154,3 +1154,9 @@ Config = 'updater.position': 'bottom: 0px; left: 0px;' 'thread-watcher.position': 'top: 50px; left: 0px;' 'qr.position': 'top: 50px; right: 0px;' + + captchaServiceDomain: '' + captchaServiceKey: [{ + 'https://api.captcha.guru': '' + 'https://2captcha.com': '' + }] diff --git a/src/main/Main.coffee b/src/main/Main.coffee index 3d95f1f5d..9d0ed1c54 100644 --- a/src/main/Main.coffee +++ b/src/main/Main.coffee @@ -551,6 +551,7 @@ Main = ['Reply Hiding Buttons', PostHiding] ['Recursive', Recursive] ['Strike-through Quotes', QuoteStrikeThrough] + ['Captcha Solving Service', Captcha.service] ['Quick Reply Personas', QR.persona] ['Quick Reply', QR] ['Cooldown', QR.cooldown]