Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ruCaptcha support #770

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/puppeteer-extra-plugin-recaptcha/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ import * as types from './types'
import { RecaptchaContentScript } from './content'
import { HcaptchaContentScript } from './content-hcaptcha'
import * as TwoCaptcha from './provider/2captcha'
import * as RuCaptcha from './provider/2captcha'

export const BuiltinSolutionProviders: types.SolutionProvider[] = [
{
id: TwoCaptcha.PROVIDER_ID,
fn: TwoCaptcha.getSolutions
},
{
id: RuCaptcha.PROVIDER_ID,
fn: RuCaptcha.getSolutions
}
]

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
var https = require('https')
var url = require('url')
var querystring = require('querystring')

var apiKey
var apiInUrl = 'https://rucaptcha.com/in.php'
var apiResUrl = 'https://rucaptcha.com/res.php'
var apiMethod = 'base64'
var SOFT_ID = '2589'

var defaultOptions = {
pollingInterval: 2000,
retries: 3
}

function pollCaptcha(captchaId, options, invalid, callback) {
invalid = invalid.bind({ options: options, captchaId: captchaId })
var intervalId = setInterval(function() {
var httpsRequestOptions = url.parse(
apiResUrl +
'?action=get&soft_id=' +
SOFT_ID +
'&key=' +
apiKey +
'&id=' +
captchaId
)
var request = https.request(httpsRequestOptions, function(response) {
var body = ''

response.on('data', function(chunk) {
body += chunk
})

response.on('end', function() {
if (body === 'CAPCHA_NOT_READY') {
return
}

clearInterval(intervalId)

var result = body.split('|')
if (result[0] !== 'OK') {
callback(result[0]) //error
} else {
callback(
null,
{
id: captchaId,
text: result[1]
},
invalid
)
}
callback = function() {} // prevent the callback from being called more than once, if multiple https requests are open at the same time.
})
})
request.on('error', function(e) {
request.destroy()
callback(e)
})
request.end()
}, options.pollingInterval || defaultOptions.pollingInterval)
}

export const setApiKey = function(key) {
apiKey = key
}

export const decode = function(base64, options, callback) {
if (!callback) {
callback = options
options = defaultOptions
}
var httpsRequestOptions = url.parse(apiInUrl)
httpsRequestOptions.method = 'POST'

var postData = {
method: apiMethod,
key: apiKey,
soft_id: SOFT_ID,
body: base64
}

postData = querystring.stringify(postData)

var request = https.request(httpsRequestOptions, function(response) {
var body = ''

response.on('data', function(chunk) {
body += chunk
})

response.on('end', function() {
var result = body.split('|')
if (result[0] !== 'OK') {
return callback(result[0])
}

pollCaptcha(
result[1],
options,
function(error) {
var callbackToInitialCallback = callback

report(this.captchaId)

if (error) {
return callbackToInitialCallback('CAPTCHA_FAILED')
}

if (!this.options.retries) {
this.options.retries = defaultOptions.retries
}
if (this.options.retries > 1) {
this.options.retries = this.options.retries - 1
decode(base64, this.options, callback)
} else {
callbackToInitialCallback('CAPTCHA_FAILED_TOO_MANY_TIMES')
}
},
callback
)
})
})
request.on('error', function(e) {
request.destroy()
callback(e)
})

request.write(postData)
request.end()
}

export const decodeReCaptcha = function(
captchaMethod,
captcha,
pageUrl,
extraData,
options,
callback
) {
if (!callback) {
callback = options
options = defaultOptions
}
var httpsRequestOptions = url.parse(apiInUrl)
httpsRequestOptions.method = 'POST'

var postData = {
method: captchaMethod,
key: apiKey,
soft_id: SOFT_ID,
// googlekey: captcha,
pageurl: pageUrl,
...extraData
}
if (captchaMethod === 'userrecaptcha') {
postData.googlekey = captcha
}
if (captchaMethod === 'hcaptcha') {
postData.sitekey = captcha
}

postData = querystring.stringify(postData)

var request = https.request(httpsRequestOptions, function(response) {
var body = ''

response.on('data', function(chunk) {
body += chunk
})

response.on('end', function() {
var result = body.split('|')
if (result[0] !== 'OK') {
return callback(result[0])
}

pollCaptcha(
result[1],
options,
function(error) {
var callbackToInitialCallback = callback

report(this.captchaId)

if (error) {
return callbackToInitialCallback('CAPTCHA_FAILED')
}

if (!this.options.retries) {
this.options.retries = defaultOptions.retries
}
if (this.options.retries > 1) {
this.options.retries = this.options.retries - 1
decodeReCaptcha(
captchaMethod,
captcha,
pageUrl,
extraData,
this.options,
callback
)
} else {
callbackToInitialCallback('CAPTCHA_FAILED_TOO_MANY_TIMES')
}
},
callback
)
})
})
request.on('error', function(e) {
request.destroy()
callback(e)
})
request.write(postData)
request.end()
}

export const decodeUrl = function(uri, options, callback) {
if (!callback) {
callback = options
options = defaultOptions
}

var options = url.parse(uri)

var request = https.request(options, function(response) {
var body = ''
response.setEncoding('base64')

response.on('data', function(chunk) {
body += chunk
})

response.on('end', function() {
decode(body, options, callback)
})
})
request.on('error', function(e) {
request.destroy()
callback(e)
})
request.end()
}

export const solveRecaptchaFromHtml = function(html, options, callback) {
if (!callback) {
callback = options
options = defaultOptions
}
var googleUrl = html.split('/challenge?k=')
if (googleUrl.length < 2) return callback('No captcha found in html')
googleUrl = googleUrl[1]
googleUrl = googleUrl.split('"')[0]
googleUrl = googleUrl.split("'")[0]
googleUrl = 'https://www.google.com/recaptcha/api/challenge?k=' + googleUrl

var httpsRequestOptions = url.parse(googleUrl)

var request = https.request(httpsRequestOptions, function(response) {
var body = ''
response.on('data', function(chunk) {
body += chunk
})

response.on('end', function() {
var challengeArr = body.split("'")
if (!challengeArr[1]) return callback('Parsing captcha failed')
var challenge = challengeArr[1]
if (challenge.length === 0) return callback('Parsing captcha failed')

decodeUrl(
'https://www.google.com/recaptcha/api/image?c=' + challenge,
options,
function(error, result, invalid) {
if (result) {
result.challenge = challenge
}
callback(error, result, invalid)
}
)
})
})
request.end()
}

export const report = function(captchaId) {
var reportUrl =
apiResUrl +
'?action=reportbad&soft_id=' +
SOFT_ID +
'&key=' +
apiKey +
'&id=' +
captchaId
var options = url.parse(reportUrl)

var request = https.request(options, function(response) {
// var body = ''
// response.on('data', function(chunk) {
// body += chunk
// })
// response.on('end', function() {})
})
request.end()
}
Loading