Support captcha solving services.
This commit is contained in:
parent
f96b24a792
commit
175350bb3d
@ -21,6 +21,7 @@
|
|||||||
"chromeStoreID": "ohnjgmpcibpbafdlkimncjhflgedgpam",
|
"chromeStoreID": "ohnjgmpcibpbafdlkimncjhflgedgpam",
|
||||||
"recaptchaKey": "6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc",
|
"recaptchaKey": "6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc",
|
||||||
"youtubeAPIKey": "AIzaSyB5_zaen_-46Uhz1xGR-lz1YoUMHqCD6CE",
|
"youtubeAPIKey": "AIzaSyB5_zaen_-46Uhz1xGR-lz1YoUMHqCD6CE",
|
||||||
|
"captchaServiceLinks": [["captcha.guru", "https://captcha.guru/en/regen/?ref=104127"], ["2captcha", "https://2captcha.com?from=7935487"]],
|
||||||
"distBranch": "gh-pages",
|
"distBranch": "gh-pages",
|
||||||
"includes_only": [
|
"includes_only": [
|
||||||
"*://boards.4chan.org/*",
|
"*://boards.4chan.org/*",
|
||||||
|
|||||||
@ -555,7 +555,7 @@ Settings =
|
|||||||
$.id('lastarchivecheck').textContent = 'never'
|
$.id('lastarchivecheck').textContent = 'never'
|
||||||
|
|
||||||
items = {}
|
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]
|
items[name] = Conf[name]
|
||||||
input = inputs[name]
|
input = inputs[name]
|
||||||
event = if name in ['archiveLists', 'archiveAutoUpdate', 'QR.personas', 'favicon', 'usercss'] then 'change' else 'input'
|
event = if name in ['archiveLists', 'archiveAutoUpdate', 'QR.personas', 'favicon', 'usercss'] then 'change' else 'input'
|
||||||
@ -571,6 +571,11 @@ Settings =
|
|||||||
Settings[key].call input
|
Settings[key].call input
|
||||||
return
|
return
|
||||||
|
|
||||||
|
$.on inputs['captchaServiceKey'], 'input', Settings.captchaServiceKey
|
||||||
|
$.get 'captchaServiceKey', Conf['captchaServiceKey'], ({captchaServiceKey}) ->
|
||||||
|
Conf['captchaServiceKey'] = captchaServiceKey
|
||||||
|
Settings.captchaServiceDomainList()
|
||||||
|
|
||||||
interval = inputs['Interval']
|
interval = inputs['Interval']
|
||||||
customCSS = inputs['Custom CSS']
|
customCSS = inputs['Custom CSS']
|
||||||
applyCSS = $ '#apply-css', section
|
applyCSS = $ '#apply-css', section
|
||||||
@ -702,6 +707,31 @@ Settings =
|
|||||||
Conf['selectedArchives'] = selectedArchives
|
Conf['selectedArchives'] = selectedArchives
|
||||||
Redirect.selectArchives()
|
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: ->
|
boardnav: ->
|
||||||
Header.generateBoardList @value
|
Header.generateBoardList @value
|
||||||
|
|
||||||
|
|||||||
@ -25,6 +25,20 @@
|
|||||||
<div><input name="captchaLanguage" class="field" spellcheck="false"></div>
|
<div><input name="captchaLanguage" class="field" spellcheck="false"></div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>Captcha Solving Service</legend>
|
||||||
|
<div>
|
||||||
|
Supported services include
|
||||||
|
<%= meta.captchaServiceLinks.map(function(x) {return '<a href="' + x[1] + '" target="_blank">' + x[0] + '</a>'}).join(', ') %>,
|
||||||
|
and any other service implementing the 2captcha API.<br>
|
||||||
|
Leave blank to disable.
|
||||||
|
<div>
|
||||||
|
Domain: <input name="captchaServiceDomain" class="field" spellcheck="false" list="list-captchaServiceDomain">
|
||||||
|
API Key: <input name="captchaServiceKey" class="field" spellcheck="false">
|
||||||
|
<datalist id="list-captchaServiceDomain"></datalist>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Custom Board Navigation</legend>
|
<legend>Custom Board Navigation</legend>
|
||||||
<div><textarea hidden name="boardnav" class="field" spellcheck="false"></textarea></div>
|
<div><textarea hidden name="boardnav" class="field" spellcheck="false"></textarea></div>
|
||||||
|
|||||||
76
src/Posting/Captcha.service.coffee
Normal file
76
src/Posting/Captcha.service.coffee
Normal file
@ -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}
|
||||||
@ -1154,3 +1154,9 @@ Config =
|
|||||||
'updater.position': 'bottom: 0px; left: 0px;'
|
'updater.position': 'bottom: 0px; left: 0px;'
|
||||||
'thread-watcher.position': 'top: 50px; left: 0px;'
|
'thread-watcher.position': 'top: 50px; left: 0px;'
|
||||||
'qr.position': 'top: 50px; right: 0px;'
|
'qr.position': 'top: 50px; right: 0px;'
|
||||||
|
|
||||||
|
captchaServiceDomain: ''
|
||||||
|
captchaServiceKey: [{
|
||||||
|
'https://api.captcha.guru': ''
|
||||||
|
'https://2captcha.com': ''
|
||||||
|
}]
|
||||||
|
|||||||
@ -551,6 +551,7 @@ Main =
|
|||||||
['Reply Hiding Buttons', PostHiding]
|
['Reply Hiding Buttons', PostHiding]
|
||||||
['Recursive', Recursive]
|
['Recursive', Recursive]
|
||||||
['Strike-through Quotes', QuoteStrikeThrough]
|
['Strike-through Quotes', QuoteStrikeThrough]
|
||||||
|
['Captcha Solving Service', Captcha.service]
|
||||||
['Quick Reply Personas', QR.persona]
|
['Quick Reply Personas', QR.persona]
|
||||||
['Quick Reply', QR]
|
['Quick Reply', QR]
|
||||||
['Cooldown', QR.cooldown]
|
['Cooldown', QR.cooldown]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user