From 6c3631fa32cd30269f3d2de45a78b227239935ce Mon Sep 17 00:00:00 2001 From: Dima Dub <38065632+dzmitry-duboyski@users.noreply.github.com> Date: Sun, 20 Oct 2024 00:19:02 +0400 Subject: [PATCH 01/19] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index a2ab2ce..c792fc6 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [balance](#balance) - [Proxies](#proxies) - [Examples](#examples) + - [Examples using Puppeteer](#examples-using-puppeteer) - [Useful articles](#useful-articles) - [Get in touch](#get-in-touch) - [Join the team 👪](#join-the-team-) @@ -551,6 +552,14 @@ solver.recaptcha({ Examples of solving all supported captcha types are located in the [examples] directory. +## Examples using Puppeteer +Also we have a separate repositories you can find examples of solving captcha using Puppeteer. +At the moment we have implemented examples of bypassing Cloudflare Challenge page and reCAPTCHA. +Links: +- [Cloudflare Bypassing Demo using Puppeteer](https://github.com/2captcha/cloudflare-demo) +- [Solving reCAPTCHA V2 using Puppeteer and clicks](https://github.com/2captcha/puppeteer-recaptcha-solver-using-clicks) + + ## Useful articles * [How to bypass captcha using JavaScript](https://2captcha.com/blog/how-to-use-javascript-to-bypass-captcha#how-to-solve-and-bypass-a-captcha-with-javascript-using-npm-package-2captchacaptcha-solver) * [Bypassing Cloudflare Challenge with Puppeteer and 2Captcha](https://2captcha.com/blog/bypassing-cloudflare-challenge-with-puppeteer-and-2captcha) From 653451c6d2a5e001ddfe747ec9872450dbea7237 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Tue, 22 Oct 2024 16:12:39 +0400 Subject: [PATCH 02/19] Add img_type param for Grid method --- examples/grid_options.js | 5 +++-- src/structs/2captcha.ts | 4 +++- src/utils/renameParams.ts | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/grid_options.js b/examples/grid_options.js index 694bbed..0d1bdd8 100644 --- a/examples/grid_options.js +++ b/examples/grid_options.js @@ -8,7 +8,7 @@ const imageInstructionsBase64 = fs.readFileSync("./media/recaptchaGridImginstruc solver.grid({ body: imageBase64, - textinstructions: "Select all squares with stairs", + textinstructions: "select all squares with stairs if there are none, click skip", imginstructions: imageInstructionsBase64, cols: 4, rows: 4, @@ -16,6 +16,7 @@ solver.grid({ maxClicks: 6, lang: "en", canSkip: 1, + imgType: "recaptcha" /* More information about the `img_type` parameter can be found at: https://2captcha.com/2captcha-api#grid */ // pingback: '123.123.123.123' /* More info about pingback https://2captcha.com/setting/pingback */ // previousId: '123456789' }) @@ -24,4 +25,4 @@ solver.grid({ }) .catch((err) => { console.log(err); - }); + }); \ No newline at end of file diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index d089469..ee3a280 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -230,6 +230,7 @@ export interface paramsGrid { minСlicks?: number, maxСlicks?: number, previousId?: string, + imgType?: string, textinstructions?: string, imginstructions?: string, canSkip?: number, @@ -1358,7 +1359,7 @@ public async boundingBox(params: paramsBoundingBox): Promise { * * The method can be used to bypass tasks where a grid is applied to an image and you need to click on grid tiles, like reCAPTCHA or hCaptcha images. * - * @param {{ body, textinstructions, imginstructions, rows, cols, minСlicks, maxСlicks, previousId, canSkip, lang, pingback}} params Parameters Grid Method as an object. + * @param {{ body, textinstructions, imginstructions, rows, cols, minСlicks, maxСlicks, imgType, previousId, canSkip, lang, pingback}} params Parameters Grid Method as an object. * @param {string} params.body `Base64`- encoded captcha image. * @param {string} params.textinstructions Text will be shown to worker to help him to select object on the image correctly. For example: "*Select cars in the image*". **Optional parameter**, if the instruction already exists in the form of the `imginstructions`. * @param {string} params.imginstructions Image with instruction for worker to help him to select object on the image correctly. The image must be encoded in `Base64` format. **Optional parameter**, if the instruction already exists in the form of the `textinstructions`. @@ -1366,6 +1367,7 @@ public async boundingBox(params: paramsBoundingBox): Promise { * @param {number} params.cols Number of columns in grid captcdha. * @param {number} params.minСlicks The minimum number of tiles that must be selected. Can't be more than `rows` * `cols`. * @param {number} params.maxСlicks The maximum number of tiles that can be selected on the image. + * @param {string} params.imgType The image will be recognized using Computer Vision. Supported value options: `recaptcha`, `hcaptcha`, `funcaptcha`, `funcaptcha_compare`. [More info here](https://2captcha.com/2captcha-api#grid). * @param {string} params.previousId Id of your previous request with the same captcha challenge. * @param {number} params.canSkip Set the value to `1` only if it's possible that there's no images matching to the instruction. We'll provide a button "No matching images" to worker and you will receive `No_matching_images` as answer. * @param {string} params.lang Language code. [See the list of supported languages](https://2captcha.com/2captcha-api#language). diff --git a/src/utils/renameParams.ts b/src/utils/renameParams.ts index 7945891..6682241 100644 --- a/src/utils/renameParams.ts +++ b/src/utils/renameParams.ts @@ -20,7 +20,8 @@ export default function renameParams(params: any) { "minClicks" : "min_clicks", "maxClicks" : "max_clicks", "canSkip" : "can_no_answer", - "previousId" : "previousID" + "previousId" : "previousID", + "imgType" : "img_type" } for(let key in params) { From 938c67a80096a4e5187bfe69adeeaaa191466b2c Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Tue, 22 Oct 2024 18:43:53 +0400 Subject: [PATCH 03/19] Add Text method --- README.md | 20 +++++++++++ examples/text.js | 15 +++++++++ src/structs/2captcha.ts | 59 +++++++++++++++++++++++++++++++++ src/utils/checkCaptchaParams.ts | 6 +++- 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 examples/text.js diff --git a/README.md b/README.md index c792fc6..0d2bed9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Friendly Captcha](#friendly-captcha) - [Bounding Box Method](#bounding-box-method) - [Grid](#grid) + - [Text Captcha](#text-captcha) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -498,6 +499,25 @@ solver.grid({ }) ``` +### Text Captcha + +[API method description.](https://2captcha.com/2captcha-api#solving_text_captcha) + +This method can be used to bypass a captcha that requires answering a question provided in clear text. + +```js +solver.textCaptcha({ + textcaptcha: "If tomorrow is Saturday, what day is today?", + lang: 'en' +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) +``` + ## Other methods ### goodReport diff --git a/examples/text.js b/examples/text.js new file mode 100644 index 0000000..ceaf3c1 --- /dev/null +++ b/examples/text.js @@ -0,0 +1,15 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); + +solver.text({ + textcaptcha: "If tomorrow is Saturday, what day is today?", + lang: 'en' +}) +.then((res) => { + console.log(res); + }) +.catch((err) => { + console.log(err); +}) \ No newline at end of file diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index ee3a280..8bae076 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -238,6 +238,12 @@ export interface paramsGrid { pingback?: string, } +export interface paramsTextcaptcha { + textcaptcha: string, + lang?: string, + pingback?: string, +} + /** * An object containing properties of the captcha solution. * @typedef {Object} CaptchaAnswer @@ -1419,6 +1425,59 @@ public async grid(params: paramsGrid): Promise { throw new APIError(data.request) } } +/** + * ### Text Captcha method + * + * Text Captcha is a type of captcha that is represented as text and doesn't contain images. Usually you have to answer a question to pass the verification. For example: "If tomorrow is Saturday, what day is today?". + * + * @param {{ textcaptcha, lang, pingback}} params Parameters Text Captcha Method as an object. + * @param {string} params.textcaptcha Text Captcha is a type of captcha that is represented as text and doesn't contain images. Usually you have to answer a question to pass the verification. + * @param {string} params.lang Language code. [See the list of supported languages](https://2captcha.com/2captcha-api#language). + * @param {string} params.pingback params.pingback URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. [More info here](https://2captcha.com/2captcha-api#pingback). + * + * @example + * solver.text({ + * textcaptcha: "If tomorrow is Saturday, what day is today?", + * lang: 'en' + * }) + * .then((res) => { + * console.log(res); + * }) + * .catch((err) => { + * console.log(err); + * }) + */ +public async text(params: paramsTextcaptcha): Promise { + checkCaptchaParams(params, "textcaptcha") + + params = await renameParams(params) + + const payload = { + ...params, + ...this.defaultPayload, + } + + const URL = this.in + const response = await fetch(URL, { + body: JSON.stringify( payload ), + method: "post", + headers: {'Content-Type': 'application/json'} + }) + const result = await response.text() + + let data; + try { + data = JSON.parse(result) + } catch { + throw new APIError(result) + } + + if (data.status == 1) { + return this.pollResponse(data.request) + } else { + throw new APIError(data.request) + } +} /** * Reports a captcha as correctly solved. diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index dbc00d0..70108b3 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,6 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -21,6 +21,7 @@ const mtСaptchaRequiredFields = ['pageurl', 'sitekey'] const boundingBoxRequiredFields = ['image'] // and textinstructions or imginstructions const friendlyCaptchaFields = ['pageurl','sitekey'] const gridRequiredFields = ['body'] // and textinstructions or imginstructions +const textCaptchaRequiredFields = ['textcaptcha'] /** * Getting required arguments for a captcha. @@ -83,6 +84,9 @@ const getRequiredFildsArr = (method: string):Array => { case "friendly_captcha": requiredFieldsArr = friendlyCaptchaFields break; + case "textcaptcha": + requiredFieldsArr = textCaptchaRequiredFields + break; } return requiredFieldsArr } From 67696a34b2638661dc718393100eabf7cdb4bd3f Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Wed, 23 Oct 2024 13:53:30 +0400 Subject: [PATCH 04/19] Add license information to README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 0d2bed9..271e6d7 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,8 @@ Examples of API requests for different captcha types are available on the [JavaS - [Useful articles](#useful-articles) - [Get in touch](#get-in-touch) - [Join the team 👪](#join-the-team-) +- [License](#license) + - [Graphics and Trademarks](#graphics-and-trademarks) ## Installation @@ -599,6 +601,14 @@ There are many ways to contribute, of which development is only one! Find your n +## License + +The code in this repository is licensed under the MIT License. See the [LICENSE](./LICENSE) file for more details. + +### Graphics and Trademarks + +The graphics and trademarks included in this repository are not covered by the MIT License. Please contact support for permissions regarding the use of these materials. + [post options]: https://2captcha.com/2captcha-api#normal_post [list of supported languages]: https://2captcha.com/2captcha-api#language From c2a7b92586fd749eea6fbe84ebd1c14ec90f488b Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Fri, 25 Oct 2024 12:47:50 +0400 Subject: [PATCH 05/19] Add Canvas Method --- README.md | 21 ++++++++ examples/canvas.js | 19 +++++++ examples/media/canvas.png | Bin 0 -> 2795 bytes examples/media/canvasImgInstructions.jpg | Bin 0 -> 14750 bytes src/structs/2captcha.ts | 65 ++++++++++++++++++++++- src/utils/checkCaptchaParams.ts | 6 ++- 6 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 examples/canvas.js create mode 100644 examples/media/canvas.png create mode 100644 examples/media/canvasImgInstructions.jpg diff --git a/README.md b/README.md index 271e6d7..c60eea4 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Bounding Box Method](#bounding-box-method) - [Grid](#grid) - [Text Captcha](#text-captcha) + - [Canvas](#canvas) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -520,6 +521,26 @@ solver.textCaptcha({ }) ``` +### Canvas + +[API method description.](https://2captcha.com/2captcha-api#canvas) + +The canvas method can be used when you need to draw a line around an object on an image. Returns a set of points' coordinates to draw a polygon. + +```js +solver.canvas({ + body: 'iVBORw0KGgoAAAANSgAAAcIA...', + imginstructions: '/9j/4AAQSkZJRgABAQEA...', + textinstructions: 'Highlight the red CIRCLE' +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) +``` + ## Other methods ### goodReport diff --git a/examples/canvas.js b/examples/canvas.js new file mode 100644 index 0000000..e4cb1cc --- /dev/null +++ b/examples/canvas.js @@ -0,0 +1,19 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); +const fs = require('fs') +const imageBase64 = fs.readFileSync("./media/canvas.png", "base64") +const imginstructionsBase64 = fs.readFileSync("./media/canvasImgInstructions.jpg", "base64") + +solver.canvas({ + body: imageBase64, + textinstructions: 'Highlight the red CIRCLE', + imginstructions: imginstructionsBase64, +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) \ No newline at end of file diff --git a/examples/media/canvas.png b/examples/media/canvas.png new file mode 100644 index 0000000000000000000000000000000000000000..f0dc728f9ce5d77a2d950f40adf72a6830af0de0 GIT binary patch literal 2795 zcmd6pdoJU0B|SypI<%X zq-QXId@vXQ6dP6+Bz?1@1^~!&Y)DqL@Wby1tP(V>)nh$oi_XKthu^=__`E9mUUWAb z;cFJ2YhiPn9V0U!!Wj=ncql!(pJf+1M>b$OGdnM(s-=F}wefLm#t%QLj7F7A8A9^G(phHVB?nlW)HsqBqQHDSw13VZAz>$!RC^SIgLOHw?KnacjP=BiY zU{o0`Gc{EEKAYjT=EUHvJ@d1Q3q(ozcbmI@aWZyB{k2~{EG~mBU*1&V7xV31D`g!l z|A%Y-V+{XS%Etqv7gpZ(v0(b_z3FVjMR9lBa{PmPk&?>Dh`F}pp?Q0Uc6{wpFP=T~ z>$sbQ_GmajiI40ic^U-vsvtcSh^5yM!*@yaN-CND@DQ^1y_Sti@+G`4{p0j1K?h5h zAJVZrJX^KY!K{t^d_VGDqIWJ^7tzH)Z5q3XlNhS!M;50p&r=Nu`>|SlU+kC*ZmFPn zX{Z*%0epM>$a#MC-K?qLYOFqB*6&Krt7*OsPevNmHsua6TaL-lTaOZ-I}&0k3i1Sh zESw*#G1?V4w+%3=Et$#0n|o#0-1hj8?9j=N31CU=QKD(NO;$gx ziZxjlCPwRv_(E7Som8SIS}0r-&vV6MGk`5Q6Dd8bw{@+d6DyEv{ZOh75b8Z%`alOY zTBJ~N(O}QW;W6xh`jz4fqg$_*PY{ocW@eko+4_teZ`~erC1)0)d^Ig^iVWPacR~i@ zOg9_=OVSGU5b$O?o&k1p$3FS@>e6EipaPe5$UD_rTO(wH3umOZrW<_0H0N0@5SVqb zL?<2W@)(G!rr}b}6Ear(2bIeaygF0N4j4Zm-sZICgRy_AZ(hZ8OFx{{_?>spPYgU&AC&!hQ;RXR!KY?OFEQY=EWnM?P=H zc)jI!0o@2QR-lMvdY-uZbVM6-p0d7&>YD zpZX~)xdLi?6NMg3y2N}CW#M$XcZ#ZhRY4l3%gjogRX%$Bqyn_(5(h(D$Iq!^W)7dB z=nz0Bd$du**p7jSE5#W+AeW|s(9kBh2nFOFd3^8KE}P3y{KD1oiPKn=Oi@lo{B=(Q zwPXIA3YrH04$fOcm*7^IMb>QfD%w!Ook*^X#Xe*im}KnIICPHHMuO69mBY}UnInUq zs62v#u-Z@Mf>9!ybpcjVev}y0o^|9o+Zhh=c}^p@`=_1eHCI2;M~MyzGs$z>%ACHJ zmb)#qlb4d;f0@c(Tz=<^uUW2)^y$tu7m_AIB+LF1s5m10V{xRxXn=Wnq;+X0n7cS& zq{WPfIs8O*t<3H?LZKj~0KxhDHN?49i$Wgksj!WLK9CgQqu7!*L?v<5%_4hukH5rx zJy&5gdOKdo1I+pwn2Ul<8q-4MmKU{QE!X8r^4jds`FRw5PgaI2p8)>jX#xw?OC=vh zTWz8eI9-#bXd@pmAspD+A4=X`wT}jc_Q)XBen4%hhxnzYP(t?8xw1X7(mMG(#_OZR z-33U){PExav@ZYMHL-^)`8q$_gcr?lx#MhYC6lPv;7U5@c<)i>6+kay(A&kX#tqPm z-x8HO9@6pXT|;1vBuw(D`Dvu0Ap2Wm5eBj9RfV>knQyJ;Y0VS8)I0YPS2dA2YJ03y z<>LgRQmN+OB^5TCu_J!9#jdZ<@Rp0O->g|uHjaBZ%s_d#YX;VR<#G!#9pol9n5MV# zMqHoVj>i^x2tjg+L#_pGp?XAiwK77O3axVk({#|=>u8W!1fuYOkE3xqL5)asip9=Z z4!Vf-j(1r{H{g5sD)MOq8GaKc z>7r0BxAVMzkFS<5qzaBWNiE-~ho&(T6WMR4Lu%wYK=7t&-;M6eiVaYf9(qf0C9mej za2RL3RDSc6EG}KdB-UT^84_p(*3ELcjV~gu%Xx93b^_a1JBY-<0o|GyZxV$eND%?n zEaNLFCGr|(esL)xSQy4QF~xx<4%0aza|r|+{f48p?o!CFWDbCr_0Ver?>#%28Q9vv z6Nt=_9w%J}7>&?a5G+&gqq}60IIUbLF%L0kM;5ecV`&}h&QQsMMmlM(^n=j0XB#p{ zaBE)!O~xI8Na$HOy7SW)3T84rMX6uB%EvV77?J3uk2*cbpkgLdQwSos3JipFz@EYp zEEFnRVB513IqZX)F*EUa!iCBsl;;TKy9tSKa}2t{wFFq9i1*Jo5^gkfI2t-9d2t|-y5=8~+(v=pKUL(?_1f+w2 z^d>Dd=?Mq~5|Xz)=e~FEJ?FkL?tAac`*2pWMl!PZ&YE-0wPyRRNtvL`11!3lI+_3# z6&3IRd;ydN;If9lvm*fL>jM%10MLQg&I8ooH!AS;w?>%;?f|E#sQ$eFtx=z*{?pFT z&`_VIJwr?Tr_<4&rKh7~prfT_U}9i6%Lq1FdggOXjLd(&|M`6{QV;fV7?lIr_uYzcs2;)HJ8hfFv=T1#hTg0m-MP zJ_QncnuZ3vI|RHA(6F99f9cw-Gi*i=X)k-S%f5*JNGEu^yoJMf5GN$}$Sahdfs>1y z=Yp_^sF=9K^&9dEib~3N?rLaiY3t~kn3|beSXx=zKX!0*dgAQz%-hG;&p#mW<*V0W z;cp@$6B3h>Q&Qi(Py3Xelbe@cP+0V(qOz*Grnc_ux7N1yj?S*`o}uB9(XsJ~$*BeG z;?nZU>aVqR{O;cG{ewfo(eWR?r~vA}v-Q6?`v<;QLB39bGN7UT!xz;lKd@7?(wx3@ z?acXGMzjw-*)Gezpku!s|FOJHXG|BJDI z=W7aJq^1IeN6iXAfn&CV9y*5lpTZcMd)&+3|T__`> zXR{%0rNLL_eEE&@g)$NQA^k-11vEDNggp*|T)5>&0XoGfKv*&1BL&b9?3^Rqv!wv| zp7|$bbDKX!Nyl;IQ<$#h;{#DLLT?AT;x~sIMY2PG<@ggR0K-`fSxJj@1J-`-SX@Az z0(=YIp#ZTK)Ebba->!q2KS+!0xTvs4{9B_vynrzC;$~~ z31Zhq0S3B5c1ZtSp0kMx^b|lnn*uyX@18?HLar_~9g>|ua{pnZBxI`@=^h366u-Db z61zeH2+L2e8=a)T0?7sGYPL9{9WRIO?ZSd6fLzmmF~87%5Mu2GF>>EGMRBLzJvLPQR4nd0A*() zp%qV2d+SgF0|mJFFFF6`74Le#m4#N7HM3G&)u!XoK z#9A|SR~&|opT|^LbQA9d>#Vx(u&>)dU{!r&B&*Fi-5sb)eB9JatoA0q;yykJ`_6YV#o$KbwRRm#*N(YRmc#$D~YsXa;NTkEI& z6=MZsdDT*AIgGF7ZYCur8XeY^*2DAfOnzHJvnDp!(&?I++1=Mr*xrRXthyO;j)4<{ z=J*Az;77LypuIV9TSFba?uk7frmC~L33*phLHv9;Btur~0S`Van<(3jw^oUv4_4!o z@jP&>LsnP9#ov5}$vE9JIJ-)n=Z`K$K0$>aW4>VsLaziM<0a(Q5@*lJ_Gca|IZY-Z zjrV!qe#xTyrSCr*PK1Io#OZAe@PdZiVX@$#qUM0XCEeS+oe-WL(tuj*-)ZdgCm4ve zS+stg9TN|MPihqGiQk&)wgM+89WIb-Adqd)c)>VdWI5bS2;DQX-?ZTX_d5JtzN^o% zuhk5j@Mzv4s!ov%2vv)cJB$RRSyH?G85Fl1Br{%*jqmmQNF}=X42f;&5g9oC*VeG>E3TIu80uVQ3V_d*vQs(AT?_N)Fv7Y>W@VW*Oj#korA z?s^3}ov0F%s&rdp)nF*2y`-^OVzfz|T1G-Js?TG2ZvsESglOHuLMD3e5x{jwFWY*+ zCUPCMc{2MzrwzK%&=S3bstvTq2%LrGK)!gi)~ZWVfEFqD>t{=?$8S|&f-sdX3WA5` zp2BnQcICDCBoe!+M`Ej1tsx{f)PhAP>UG-a;WyZu3uBGwUmrR)0wb$;zq5b7!xN^& z`nct+h*jXp<^}vyRR@DGK`z5MU znMiF%Rp}4B;cE2@JgF>L z93i?p$c)>_)W$==LBPAN(%k)UeJ1=x_tX8S6FR!-UWH19F2l~!oL?ma;WcSTcPxkU zepCe&^S(ao=_J=8Mte~0Sqi&}=!BHN#%#%z5weZPZ>;=K6@a*jI(mpf{Lw<&CuHvJHT8W5Q$d|;`lLb#$AH4wR>cOBmF!*)QDF{oq2=Dj zuk}7()PqkzuhX9Mq}(SHF-|^zYhm=qhsZ}1-~rL<1Z~$J$9OpLP&SXphuvY_C)5Z-hW3e~V7*<*n+fh3N@MYo8PA zu8;FXSk(6;$fHVEUYas`K_uU?6Ny9b8~6BAB+ z=)22(N+%K82>Yt+w^Q1Vi*?dEt(%e0@YdMaD6w(Nv2sj4uqo5P2Fhq)sXV&gciVfp zw`a<(#&5V6b7$|Mra=c+(?(|cQBtLE-2@Fxh+>K>u)9fwKsFM%9H!4^pfB;cl#teE%#&$i>F+#r)98mu6R+*Yv z_H;mi@5pMm?2Wiw>+FK;uClVB@qVI=+yVud%szm4Oi9kiMXNgeQ98dCzkPDGMmn8j zZ#gQe?qF7~e8;J81QIPm$A9IM&J({KkVQ|@nk1imwH-ee_*i5+Y4x-J+;L5nsTP9j z*Dcj^AIfAFP$ah2`TUN0efwLuxOTPsR``?%W_O23AtHJc4uH za}zZO&&GlsRnNll_HD9+wH$fLH>sO$-ii`X&(EY*Dw-qF=Q`-@PEUE-v%>UB`n!AT z+I7~@@0*$N*oU%wwm#y{99+EtI$E=2vye%=EyoOE2m7T@k&>6(6)V*DXv{=u^sxb%bbIFB&$S!X1R zx}1Oi#t_KY|-6%aOvbpCfqr@s>3p1XFaLXrMg6Y z#oE$2*`Z!^?^g^Dk(1mOLxfEdvdr*Tafc+qD5{oW^60_Ki*Lbz`|fm{%pAJP|1bQJ z+*c6BUSCq>ZTXimAFVr|5jY%{8LBW$kWl4cGTHXI)ZnDXCIQhKXnO~_+`AIkOvP!d|C z!8SNyp&h&^E^TS=Jx`|xXZW046FK>|TZpw?owun(RZp)jxSFHe@8WxUkfR;DHehg41Q&oppJvwu~n_4Q@^Wy7N;hq)S%GtmB*^R&As2uA=J53*Yg*EN5&gr=ziZ z^kR6p2FH#}`Z_WQw>ntU`d1js@hFddQD=au?@Q#oE%OLsPP;_RRGNB*u;vOVefOWPY1V7koKajp?J

V+TI^FK@TVUylIc1rfao1Ga-!6e0_6I7gOM7IJq1Yo zIF8vgucZJ(^~#b*HElab0(zutq_`PHTC#>D$yoK=L6Oo)L6Z=2Vz`h3tl3nxj0X_S zkllm9+C@zf2PsjhY4ny*#EWmS`GsKfN|?4`%|D9 z@U)Zq!eiRM{BG1JSwa7nXz|KQ(ZR_Jho2rI6bn81$acO9uuCC?`4MkPNV<^ z*d~n;j0=Pxw4A5s2|=Fd>sjZj83c#P-KXZIvL3}<6@B-Vv^$q8KYWmZZ%=K}LGX8$ zao}9rQiuC;XqA%wLi(G0hcxikdJIS6KDH1F1`mvqkh94lGj&{s;n>~j?+1cy6G%7R zk|fj>$fR1?a#{UW*$zx_$1r^AOu7ds&@BQopD@=#zDOv{nG1N9iwbw0f)~?Ge@_r3 z*0GZRI&w%(ifLmVheF9S&`O7nTwMAs!ZXm|h6{)g{N^*|9}4M|PO4QNI#69YRsED& zMUH>_d)s*}rDNDaW=bh`XJV)2tKsJU;yH#Vfv=;lb{D3Pa-Glq!Y13rBYdsPQOe-g z5%-jtXU4#k3RVimfO&*r_4im5jcky^?g+Sy?RGjj+g}iRJ$H(ewdm5x^r@BGZxlO4 zd7I>9+Ka5xGZwalx0XiLoeM>#4^J{PI8yI}(dj;0tMYsAOFUjOj}i-?)J{!xW>!fm z3`#SfTc{y@jI%qo0oSG1D2#Afi}YGu2szHLa`bb&`>WHI!eR_$zHgv)I>a*@7qVb~ z1$Cg!>$`d$GRwYq#*+GZ>;Cn*P*i1p493Z-N?ett)+`I1TxU{xotd+nzT) z{$*cChukZ?j~A(xo<}R4)g()~Ubv5I$2og&6IF;OATG5IqeF|udPeM>pH$7cAyptS zWD7S1SaK&6?th^GKeoX{W#}~u&^3cM*#P~Sk24ls$TLXi0Y1b)>T&MC%l+2uzET>l z{LQyE^wpe_Z3WE_>b*Oy)fvgdS&AnpnSDJJ?MAp(x;34Q;pD|yHdiT&2&3mMzH6~n zN}cqN@USU?ej}J=j4*Fac0PRX$ySgv{AgmDw(Xq@)O;lxy6Xtx;GiK2;AHp$ zAu`y+O=2NL%)iF-Nu?g=Ve$+aeOr<`G0z%uKbN%Jaxio3KX(z#Q-|JPw^p5_YH)B~ zD1CNkh%5~^=_xpl_&I&s@r)%V@@n5Dl{*jPzSB+RPa)V{P^?X-tl-u)odXee^i4mk zryWX+H26f3=1aHey-ZmI8I~g!xmySgD-F($ghI2(G~@8?pZQ!S$wH;v`8+wJ!>Kbr zjvMl1i&K9jb7H3pj)q>np0Lnfj@Rfb@ufGe3!^CO2$SfZs~+F3f|SBW=HM z6CrR?q^f~~VNp>&sIZzjT+|x*Qe*PaPwQKXddM5ILerNOZ9kUpF7hi| z@XQ-VS|7GT-^e#f{MbKJK3=jM@bT+z!tJv4o=$k7$=mN&Z}E-)^6K)u0beXv7LLg0 zZkONT>cSpXR`28vgrzv&P7w%WwKGW85*aNSJ%*3XxQ4*-J?kn^f|PrlPzfut$~(Dx zAO6G?@%Y6(WQ(2pdH-xH!VYbO6bV{9LqLqT;!2LAInlzUbvk)Jh2EYj(A-~m(+^*U zML;=88hF3X3PN_)-*O?QcOw!kf@WsTMn9O7r~L;GRtcr}vkP0DudC49 zwyxb%8iOUXUF%a}rqz-oT#*{=$-MkpvCLsA8gbZRKyFSXPCsC=;WA&+qJI$~v zt+*y`!hO3zZ$lOxr#!;PoDc(%s!)6Hp-WnBLxNz?&10+GuSv20x$DOBrBT6||ma|FJU~{>x8GwN>Lm zHizWBr1WXim7LPD1MAr-lqb0jAwK*YO%R*wD7~`s1dAC(%P_rjJ*U!J@91qZQaxNx z{pH%0MUxm}3|YDQqDj;xjX&;Nql|e)b-n-QPN_HlZS3p{e`hc9hUkQBt*Fq0B^G6i z)q{MzpxtN#(i2;FL$83O;p2Na1e>mzTw$x=bY}0Yaqbpf?vNY>6@O?V$?fG|_cidN zEfMS&9fwP%Y|dFR-tRsXy|H5NFH(uW*4DvZM2wHlHhC|EO=z$&87zwt9BRcoa4=M6 z6qy+0yEmDS(mBY4Ueq#brYck zz6X!9ngQS!i0Uzn5$@o#+dvItd(ya|reB$9(H(?Ty~REmQ(ouWRnjo;y9G0g?p`$! zPPwn6Df@JJXkC0dZ%gvH9-_e5BY8bm+1)rYEv4Ga`9@REft~gS)NO64_M}Yx()HM( zt7G~1ESKi_sD1;0+H1s{;G2ZW#h7yk+Bm}~b(UX&uqbmqNr$?Mgt7bY6Cgt3yNh8O z!U-A^Jqj$(I(xK9XgoT4U*=7g^vI3AN2^TL5XNi zxB>L(xr8GLnPKa{O#YpskktpZkaIuSdc0MWxZVmp_@befZ(*ZxD0U_&s?lyQSdWF zNt?>Vss=)eT0@HKsfEAG3+JYzbnNcm53skasCT(L_-=7EvE1UuJed0+ z=_!N-LkiYepFNFuC1el3cD9~|#j{>fkd}MR*55_3BoEwwa!Jx+?Nz*MU1`t12aH+H7Y>u2eT{!L!$jYurorATbb@mGK+zE2I3TAHqetnVGvihirmf|xf;i9f_!`H+4*9KV^6ri44~$#NyBlh~P!d%+2q`>y0C z6yOFTDT{l70PdLblyAVvPgQc{>VF zZoNnWbT@yYSLWC-O93*t&RwYYJmiQSjn~G>OqHx2W={4nIF>ny= zD|Cl1vhKGO-8NP3yH#!}8q@M*`?Fhqm`^idw9@VNLJO~7Cf=WPTMx!)1g^e;J~9;W z*IKNO0^=F;ii%+$4_3Y9wL`Cd>yBkjFYH}&MeZfHpR%&qmn)i-$UU=y1SJG$|%3)A841E-Ytqgn!S6%B*VeEuJ>_%r_{xpJbDqxx-O!_u{@}`%v_% zak?&(xUK8#`2MeeT#o%tl2ROaeu1`ungYD2L6TzZ?hv)f?RKgsDJi^h=PjoOa(;GQ ziZc0}-d`0!C;CuGviQMy1+ji+xtFo35OxQ}qM|T?1_#kEP3R%wF~4OjdMkIP^} zj$5~*Ypd-jqJV&jhs7MoSQA@}s z)6?SZTffrORPXs)SfvTg9jHhissA9i_C>Iu2wd)R_ZKTjHMC~;+AX4mj^)vNTYKfP z=R`XneOQ0ErfXztOfDnE?~Zb8qE0~{Vt5cg>^SlAg*iW;eDxw2JBA+28K*pPS8c!j zy{MR%F`9LcW2M2pUd;aUeo=pnc)r;E_g7LaEcUh3T=@e{7p-%wqtTAXyYF2M{GFO$4OQ&qlO4j$jes9#YJ^xlVR7;UD@EC6etpve~XPwXr zk5)-E2Rse^YP*tX_2~8D=epX2M~@$5Q!Qw87(#CZ#ABn2EaQqg8Ul8D-D?_44>RZ1 z$@ZJ-6`L^OI`q(3BYDdZ_2g6JVI1H8jMV?DPsu(C@MO!Rd+_?ST85#D{)*G~Ca-54 zK>*3{J93u-OzHAm;1{?TJJ>NS{vhYIXm7J{g~4T zmKUgrsB>wP-0iONJ4o=||E=0_=}o7*a-d0J`AN&~e2ZNKXV0sEAi)!b@44cSij+LQ z?;O5nH?pN=G16cMz)r={GBsVlh~I(f{R&Jy=#Ov;SUy6!ybzhp*!=ln5!V+yEcXCi zb`E&9G1L@`bE~)ZzoQ#@_sLRhKfA-j(431jtgu4=b4n$v5dC1)a)bru2+{}D*S$V> z_Hk{v$CDz{IFyX^!4@JfncWCBqIJ{@VyYTI2)NPzF<~M0_qeM2$Hv@&qz!V-Hj{%i zjrAkN36r_WTH6`mqQ9I>78jr=nn4IX&zr}WG`-=?z3 zw+9Cn(O>(et#%VFchX2!-hgsroMCLzGg~b~znL`M6bvf&=ptt>J>z-MNPW$?ZGV-g znftdPK}f4Z8oIFBxpn9ENZF;T@b)o14>zG#V(@o!-p;jI3Xnq!bxAK6Hr5EDO<4_K|oxcZF5{B)=(z=o|!hYbbk!0JB0|4f=SwgUdsnBBK98VWF;mkMT)62>7!Me=vD z)JYZ+4tcpp_|nfLzu1=g#qcyLLjZd^M*CzvmOZoiMMB`qP`a{KG6NXTi=W0Bo&-80 zkFBKbt@AGAv;4?n%|B;v{Ik01C^zW7{tjYuC{r2NRerB6FSpMyXm-q|o&xxe?UrxM z;Y?wZ9-XL4$Ex}F4P2j)@GFTNQ!~(Mw=GiW7QNwqS zsTIWoPe~h(Lw~4#-d6EG_g?DRD+i)0Q}G4SD(Bw4h~A5W;LM@1c2@|(i-zF}SsZxg z(oYrAOGE8$PkT=fYQB7uqPqE(F+QBeE5s#kYi&ML=Ai5(R#gojcc=WdPmKDMWYjPN z88=-%sVe1}vg@$KHfVlZdAxHe5;H1`E}LE_57ySA1N3!miuCKP>bKlD>uruV$0w0b z?8&9bk|3cpj~UOWF-OK0E4tIOTWi@*h6u2y$j34SVYkjmZ?jkk%SLrnpnK@@t8wEJ zBYEUnhHDOWhef_f6D=;keSqB`(y@Wnm$Vyo-QSVxgD=-QraAT-zSB{Epw{|WV19gV zj%w)KG?YxA>N6iAzdlSpug}@%eehyJCiVLH2)78HE-MZWzbrWnF~_14!FBRVU7C>J z(fd*6h0g{LX_zn7qPo<>o`sfi#aH0I*v2lW6m1W0Zb&%eqo+ym71r;$+@n4Yecy)~ zr0V=;Ri<-Gmx5CQG#hO=sn>OS(n1L)zJiv7bj5L^4XULtKh>m z34I|8UEAb~)+B>;?ee$m>20jA8&&l+Jy(ZgiaPTj1zKdb_(%WcGXBcN#B?SwH438= z7_7c)KApYpgBQMVzV%_QqJH1K*BNd-DHzU}Ll3juxNDyxCHDpQ=0S%G_}}$1=we=k zNX0ylP+ZWB=wi<*Hs5*KaP@bL1|jTZ{@1eDnJXU?lmvAI<8{BthB4-N(W!dLDq$Pc zg}N8hmVI{D*0wG$BGpk52LcehDFOZlXSH>sOd!X>eN7GF>)!eOX|)9fK&OQ``%kx? z_m^w8ke9CeWIl5?!SFqA$Z!VLIy0@AtAOmYTV3dd3@M3)T-7rY>$##m!*g2jW4V)* z@7K6pLnN$b?M4b7+4HoQnip+3kNWH}h<&P$6Z*TsOqbl^F7f18&`d8h@z}V7rhZiz zfxd7(d76wl)&DYE2W!Y;J<(b3Gg8bWk>0}?-84%KfEs=ek+icQLj8pu;`e)B2X~Nd z^K|YR(D|(m*ko0SWcL}_$Ri6WFZHCX6O5IJ=+3Be!4$PzTv;-c?83?xG z4q(C({@jW>rJ0)B`@0h$K__iwC6K!3f3qB5;_p8gDE7an27meN5IM@Azsvd~$!>TR zvKHvVG9m>J4X7wUye^0)#8ICVfyjDTHX%Oqr+>Z)brv1brl~c5gv>Abl4BMz3W6Ct z8hBB1N2Vd@DleBYV?N5(?#{3M-FAU$yO$phV+~cEF)X?2?NLp_SUd ziC~&q+Kqb(<62YG`1YKk>=W>)jx|0_0`Jc#FCn2=5ylqV0$;C2USFe086S7Oa^aNR^WuwQ?C#JjGYwf{gjC{9|N2GR zHeN#x|0qj0ExU5dgtO?1JLggaAN@L|8JTfSG+$};M#rFmBIEVP`4>DJEF^p_^uG8G z2DmEOUppWDQM|iQrOMBd*tFA^Io>fhW!N!S=`f2@h_1>Tdps0BG;)$~)|166w>E;E zZ_Cag&+!kT1Gjo-;{ys=MRl;kly7%|x8|8LM_JZA}#fa85H4TEJk5!Npnt zjimrpYk^huQ?@N9$qtZow$PIL6qeSDS+~wKSV#7h>7|YqZ>|4$m5-5ob^q(MIr?KR z-#D)>>PxP*XPkpbO8u|QDz(IB6z-l()Etv4B>$JPOw`n{&JdQx`rDLSMu!kTmv_7z zi^}5+W@R&IB&LR|T_&dKY%Ojlf^=^xCC>ZT?sSau5YsZZENQTX&Rb}-UxNjQo4E)(W|Jx2d z@iw{{kg)?=5z)9xNX53c`^QH(-J2brJ>?y~S#oh2iYiZoB~6E9R8@k<4#$S?_tf=# z-PP3Y`Tdig=9DZmvx>#gQ3;yUU(OJp`KG4nm3s56NvPSPko`ppu$g~xUSO0k{$`e= zRkiRWH>GzH`>6C}GWSa=$`NTnp#7at+%f_k-8@c5r|Qfg)kF?Gw;P%kSA9a}PF$?F zRn2hJ#>3kRYhKd7ncHamEOT#lZ{Jkp=HW~5zo%5Da_@(a^o7$YyB)`4@@_9yYM!*H zW;~8|icKahymvTivapzN^tWn9S0*OG(w>k{y5z{5*uPXgGt}N2r=?D0Bsr%48c7=o zjg0H}@aP(Ail1llYvV=q<=M*0(wof$SNf>YIbIa#Tuba{R(ygj=YC)0Z=AR`I#1 z2Co?~52#SVN}s}B5=h@FuaPtxGjBL+rUh1G(rZ4FFxc^-Y~k*!RbB|1)ao`J#a@>2 zdiGJYVg24D%~dTpL;D3OPt8-GB(_YcKTv<>&NtFP8k^)ZJiQnC#aeiR0w_viCB_RS zMst?M<);IyXScuz#hT|dc=i%v^G^yEIv*~4J^m~1P`Br+xTBk{%eN*wG#fdSN=cI3Gw^qNatbm=;$Us#NgM_!#53r zShq7hFs6Z1HZICG2j!|^>!YD(;%`dbF7J5uTC^P0?f547PSf@k_o};z%dvCA(0dDi Q30<8yt; { throw new APIError(data.request) } } + /** * ### Text Captcha method * @@ -1479,6 +1481,67 @@ public async text(params: paramsTextcaptcha): Promise { } } +/** + * ### Canvas method + * + * This method can be used to bypass tasks in which you need to circle an object or line in an image. + * + * @param {{ body, textinstructions, imginstructions, canSkip, lang, pingback}} params Parameters Canvas as an object. + * @param {string} params.body `Base64`- encoded captcha image. + * @param {string} params.textinstructions Text will be shown to worker to help him to select object on the image correctly. For example: "*Select cars in the image*". **Optional parameter**, if the instruction already exists in the form of the `imginstructions`. + * @param {string} params.imginstructions Image with instruction for worker to help him to select object on the image correctly. The image must be encoded in `Base64` format. **Optional parameter**, if the instruction already exists in the form of the `textinstructions`. + * @param {number} params.canSkip Set the value to `1` only if it's possible that there's no images matching to the instruction. We'll provide a button "No matching images" to worker and you will receive `No_matching_images` as answer. + * @param {string} params.lang Language code. [See the list of supported languages](https://2captcha.com/2captcha-api#language). + * @param {string} params.pingback params.pingback URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. [More info here](https://2captcha.com/2captcha-api#pingback). + * + * @example + * solver.canvas({ + * body: 'iVBORw0KGgoAAAANSgAAAcIA...', + * imginstructions: '/9j/4AAQSkZJRgABAQEA...', + * textinstructions: 'Highlight the red CIRCLE' + * }) + * .then((res) => { + * console.log(res); + * }) + * .catch((err) => { + * console.log(err); + * }) + */ +public async canvas(params: paramsGrid): Promise { + checkCaptchaParams(params, "canvas") + + params = await renameParams(params) + + const payload = { + ...params, + recaptcha: 1, + canvas: 1, + method: "base64", + ...this.defaultPayload, + } + + const URL = this.in + const response = await fetch(URL, { + body: JSON.stringify( payload ), + method: "post", + headers: {'Content-Type': 'application/json'} + }) + const result = await response.text() + + let data; + try { + data = JSON.parse(result) + } catch { + throw new APIError(result) + } + + if (data.status == 1) { + return this.pollResponse(data.request) + } else { + throw new APIError(data.request) + } +} + /** * Reports a captcha as correctly solved. * diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index 70108b3..de17873 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,6 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -22,6 +22,7 @@ const boundingBoxRequiredFields = ['image'] // and textinstructions or imginstru const friendlyCaptchaFields = ['pageurl','sitekey'] const gridRequiredFields = ['body'] // and textinstructions or imginstructions const textCaptchaRequiredFields = ['textcaptcha'] +const canvasRequiredFields = ['body'] // надо проверку, если какая нибудь инструкция текст\картинка /** * Getting required arguments for a captcha. @@ -87,6 +88,9 @@ const getRequiredFildsArr = (method: string):Array => { case "textcaptcha": requiredFieldsArr = textCaptchaRequiredFields break; + case "canvas": + requiredFieldsArr = canvasRequiredFields + break; } return requiredFieldsArr } From 25293451796b61f902086076a745190c7277cdad Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Fri, 25 Oct 2024 16:09:59 +0400 Subject: [PATCH 06/19] Add Rotate method --- README.md | 20 +++++++++ examples/media/rotatecaptcha.png | Bin 0 -> 8647 bytes examples/rotate.js | 18 ++++++++ src/structs/2captcha.ts | 70 +++++++++++++++++++++++++++++++ src/utils/checkCaptchaParams.ts | 6 ++- 5 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 examples/media/rotatecaptcha.png create mode 100644 examples/rotate.js diff --git a/README.md b/README.md index c60eea4..baa4033 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Grid](#grid) - [Text Captcha](#text-captcha) - [Canvas](#canvas) + - [Rotate](#rotate) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -541,6 +542,25 @@ solver.canvas({ }) ``` +### Rotate + +[API method description.](https://2captcha.com/2captcha-api#solving_rotatecaptcha) + +This method can be used to solve a captcha that asks to rotate an object. It is mostly used to bypass FunCaptcha. Returns the rotation angle. + +```js +solver.rotate({ + body: imageBase64, + textinstructions: "Rotate the object to the correct position" +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) +``` + ## Other methods ### goodReport diff --git a/examples/media/rotatecaptcha.png b/examples/media/rotatecaptcha.png new file mode 100644 index 0000000000000000000000000000000000000000..4602d7d1645e23ffcfa1ba296834b102eb22d362 GIT binary patch literal 8647 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 literal 0 HcmV?d00001 diff --git a/examples/rotate.js b/examples/rotate.js new file mode 100644 index 0000000..e7a50be --- /dev/null +++ b/examples/rotate.js @@ -0,0 +1,18 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); +const fs = require('fs') +const imageBase64 = fs.readFileSync("./media/rotatecaptcha.png", "base64") + +solver.rotate({ + body: imageBase64, + angle: 15, + textinstructions: "Rotate the object to the correct position" +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) \ No newline at end of file diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index 4241a04..810db09 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -245,6 +245,15 @@ export interface paramsTextcaptcha { pingback?: string, } +export interface paramsRotateCaptcha { + body: string, + angle?: number, + pingback?: string, + lang?: string, + textinstructions?: string, + imginstructions?: string +} + /** * An object containing properties of the captcha solution. * @typedef {Object} CaptchaAnswer @@ -1542,6 +1551,67 @@ public async canvas(params: paramsGrid): Promise { } } +/** + * ### Rotate method + * + * This method can be used to solve a captcha that asks to rotate an object. It is mostly used to bypass FunCaptcha. Returns the rotation angle. + * + * @param {{ body, angle, pingback, lang, textinstructions, imginstructions }} params Parameters for solving Rotate Captcha as an object. + * @param {string} params.body Base64-encoded image of the captcha that needs to be rotated. + * @param {number} params.angle Angle to which the captcha needs to be rotated to solve it correctly. Value between `0` to `360`. + * @param {string} params.textinstructions Optional param. Text instruction that will be shown to worker to help solve the captcha correctly. + * @param {string} params.imginstructions Optional param. Base64-encoded image instruction that will be shown to worker to help solve the captcha correctly. + * @param {string} params.lang Optional param. Language code for worker to use while solving the captcha. + * @param {string} params.pingback Optional param. URL for pingback (callback) response when captcha is solved. + * + * @returns {Promise} The result from the solve. + * @throws APIError + * + * @example + * solver.rotate({ + * body: "iVBORw0KGgoAAAANSUhEUgAAAcIA...", + * angle: 15, + * textinstructions: "Rotate the object to the correct position" + * }) + * .then((res) => { + * console.log(res); + * }) + * .catch((err) => { + * console.log(err); + * }) + */ +public async rotate(params: paramsRotateCaptcha): Promise { + checkCaptchaParams(params, "rotatecaptcha") + + const payload = { + ...params, + method: "rotatecaptcha", + ...this.defaultPayload, + } + + const URL = this.in + const response = await fetch(URL, { + body: JSON.stringify(payload), + method: "post", + headers: {'Content-Type': 'application/json'} + }) + const result = await response.text() + + let data; + try { + data = JSON.parse(result) + } catch { + throw new APIError(result) + } + + if (data.status == 1) { + return this.pollResponse(data.request) + } else { + throw new APIError(data.request) + } +} + + /** * Reports a captcha as correctly solved. * diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index de17873..d6206a2 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,6 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -23,6 +23,7 @@ const friendlyCaptchaFields = ['pageurl','sitekey'] const gridRequiredFields = ['body'] // and textinstructions or imginstructions const textCaptchaRequiredFields = ['textcaptcha'] const canvasRequiredFields = ['body'] // надо проверку, если какая нибудь инструкция текст\картинка +const rotateRequiredFields = ['body'] /** * Getting required arguments for a captcha. @@ -91,6 +92,9 @@ const getRequiredFildsArr = (method: string):Array => { case "canvas": requiredFieldsArr = canvasRequiredFields break; + case "rotatecaptcha": + requiredFieldsArr = rotateRequiredFields + break; } return requiredFieldsArr } From 7df649b3dd22d563dbe2a0811ae0c8f81b31cfa8 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Fri, 25 Oct 2024 17:17:12 +0400 Subject: [PATCH 07/19] refactor captcha parameter check --- src/utils/checkCaptchaParams.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index d6206a2..8915d81 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -22,7 +22,7 @@ const boundingBoxRequiredFields = ['image'] // and textinstructions or imginstru const friendlyCaptchaFields = ['pageurl','sitekey'] const gridRequiredFields = ['body'] // and textinstructions or imginstructions const textCaptchaRequiredFields = ['textcaptcha'] -const canvasRequiredFields = ['body'] // надо проверку, если какая нибудь инструкция текст\картинка +const canvasRequiredFields = ['body'] // and textinstructions or imginstructions const rotateRequiredFields = ['body'] /** @@ -127,21 +127,13 @@ export default function checkCaptchaParams(params: Object, method: string) { } }) - if(method === "bounding_box") { + //The parameters `textinstructions` and `imginstructions` are mandatory for the methods `bounding_box`, `grid`, and `canvas`. + if(method === "bounding_box" || method === "grid" || method === "canvas") { if(params.hasOwnProperty('textinstructions') || params.hasOwnProperty('imginstructions')) { isCorrectCaptchaParams = true } else { isCorrectCaptchaParams = false - throw new Error(`Error when check params captcha.\nNot found "textinstructions" or "imginstructions" field in the Object. One of this field is required for "bounding_box" method. Please add field "textinstructions" or "imginstructions" in object and try again.\nPlease correct your code for the "bounding_box" method according to the code examples.`) - } - } - - if(method === "grid") { - if(params.hasOwnProperty('textinstructions') || params.hasOwnProperty('imginstructions')) { - isCorrectCaptchaParams = true - } else { - isCorrectCaptchaParams = false - throw new Error(`Error when check params captcha.\nNot found "textinstructions" or "imginstructions" field in the Object. One of this field is required for "Grid" method. Please add field "textinstructions" or "imginstructions" in object and try again.\nPlease correct your code for the "Grid" method according to the code examples.`) + throw new Error(`Error when check params captcha.\nNot found "textinstructions" or "imginstructions" field in the Object. One of this field is required for "${method}" method. Please add field "textinstructions" or "imginstructions" to captcha parameters.`) } } From 2ac2b5933a0c838699687038afbce2d4d595d8cd Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Fri, 25 Oct 2024 17:18:36 +0400 Subject: [PATCH 08/19] Update Grid example --- examples/grid.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/grid.js b/examples/grid.js index 0b9c9b3..0f26842 100644 --- a/examples/grid.js +++ b/examples/grid.js @@ -3,11 +3,15 @@ require('dotenv').config(); const APIKEY = process.env.APIKEY const solver = new TwoCaptcha.Solver(APIKEY); const fs = require('fs') -const imageBase64 = fs.readFileSync("./media/recaptchaGrid3x3.jpg", "base64") +const imageBase64 = fs.readFileSync("./media/recaptchaGrid4x4.jpg", "base64") +const instructionsImageBase64 = fs.readFileSync("./media/recaptchaGridImginstructions4x4.jpg", "base64") solver.grid({ body: imageBase64, - textinstructions: "Select cars in the image" + textinstructions: "Select all squares with stairs", + imginstructions: instructionsImageBase64, + cols: 4, + rows: 4 }) .then((res) => { console.log(res); From 16b131660fc76ee24fa986639d25e03c27bbbec3 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Fri, 25 Oct 2024 17:55:47 +0400 Subject: [PATCH 09/19] Add KeyCaptcha method --- README.md | 23 ++++++++++ examples/keyCaptcha.js | 18 ++++++++ src/structs/2captcha.ts | 76 +++++++++++++++++++++++++++++++++ src/utils/checkCaptchaParams.ts | 6 ++- 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 examples/keyCaptcha.js diff --git a/README.md b/README.md index baa4033..f6d4353 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Text Captcha](#text-captcha) - [Canvas](#canvas) - [Rotate](#rotate) + - [KeyCaptcha](#keycaptcha) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -561,6 +562,28 @@ solver.rotate({ }) ``` +### KeyCaptcha + +[API method description.](https://2captcha.com/2captcha-api#solving_keycaptcha) + +Token-based method to solve KeyCaptcha. + +```js +solver.keyCaptcha({ + pageurl: "https://2captcha.com/demo/keycaptcha", + s_s_c_user_id: '184015', + s_s_c_session_id: '0917788cad24ad3a69813c4fcd556061', + s_s_c_web_server_sign: '02f7f9669f1269595c4c69bcd4a3c52e', + s_s_c_web_server_sign2: 'd888700f6f324ec0f32b44c32c50bde1' +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) +``` + ## Other methods ### goodReport diff --git a/examples/keyCaptcha.js b/examples/keyCaptcha.js new file mode 100644 index 0000000..b4dfb55 --- /dev/null +++ b/examples/keyCaptcha.js @@ -0,0 +1,18 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); + +solver.keyCaptcha({ + pageurl: "https://2captcha.com/demo/keycaptcha", + s_s_c_user_id: '184015', + s_s_c_session_id: '0917788cad24ad3a69813c4fcd556061', + s_s_c_web_server_sign: '02f7f9669f1269595c4c69bcd4a3c52e', + s_s_c_web_server_sign2: 'd888700f6f324ec0f32b44c32c50bde1' +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) \ No newline at end of file diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index 810db09..a3c9765 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -254,6 +254,17 @@ export interface paramsRotateCaptcha { imginstructions?: string } +export interface paramsKeyCaptcha { + pageurl: string, + s_s_c_user_id: string, + s_s_c_session_id: string, + s_s_c_web_server_sign: string, + s_s_c_web_server_sign2: string, + pingback?: string, + proxy?: string, + proxytype?: string +} + /** * An object containing properties of the captcha solution. * @typedef {Object} CaptchaAnswer @@ -1612,6 +1623,71 @@ public async rotate(params: paramsRotateCaptcha): Promise { } +/** +* ### Solves a KeyCaptcha. +* +* This method can be used to solve a KeyCaptcha. It is mostly used to bypass captchas that use KeyCaptcha technology. +* [Read more about KeyCaptcha](https://2captcha.com/2captcha-api#solving_keycaptcha). +* +* @param {{ pageurl, s_s_c_user_id, s_s_c_session_id, s_s_c_web_server_sign, s_s_c_web_server_sign2, pingback, proxy, proxytype }} params Parameters for solving KeyCaptcha as an object. +* @param {string} params.pageurl The URL where the captcha is located. +* @param {string} params.s_s_c_user_id The user ID provided by KeyCaptcha. +* @param {string} params.s_s_c_session_id The session ID provided by KeyCaptcha. +* @param {string} params.s_s_c_web_server_sign The web server sign provided by KeyCaptcha. +* @param {string} params.s_s_c_web_server_sign2 The second web server sign provided by KeyCaptcha. +* @param {string} [params.pingback] Optional param. URL for pingback (callback) response when captcha is solved. +* @param {string} [params.proxy] Optional param. Proxy to use while solving the captcha. Format: `login:password@123.123.123.123:3128`. +* @param {string} [params.proxytype] Optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. +* +* @returns {Promise} The result from the solve. +* @throws APIError +* +* @example +* solver.keyCaptcha({ +* pageurl: "https://example.com/captcha", +* s_s_c_user_id: "12345", +* s_s_c_session_id: "session123", +* s_s_c_web_server_sign: "sign123", +* s_s_c_web_server_sign2: "sign456" +* }) +* .then((res) => { +* console.log(res); +* }) +* .catch((err) => { +* console.log(err); +* }) +*/ +public async keyCaptcha(params: paramsKeyCaptcha): Promise { + checkCaptchaParams(params, "keycaptcha") + + const payload = { + ...params, + method: "keycaptcha", + ...this.defaultPayload, + } + + const URL = this.in + const response = await fetch(URL, { + body: JSON.stringify(payload), + method: "post", + headers: {'Content-Type': 'application/json'} + }) + const result = await response.text() + + let data; + try { + data = JSON.parse(result) + } catch { + throw new APIError(result) + } + + if (data.status == 1) { + return this.pollResponse(data.request) + } else { + throw new APIError(data.request) + } +} + /** * Reports a captcha as correctly solved. * diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index 8915d81..c2e253c 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,6 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -24,6 +24,7 @@ const gridRequiredFields = ['body'] // and textinstructions or imginstru const textCaptchaRequiredFields = ['textcaptcha'] const canvasRequiredFields = ['body'] // and textinstructions or imginstructions const rotateRequiredFields = ['body'] +const keycaptchaRequiredFields = ['pageurl', 's_s_c_user_id', 's_s_c_session_id', 's_s_c_web_server_sign', 's_s_c_web_server_sign2'] /** * Getting required arguments for a captcha. @@ -95,6 +96,9 @@ const getRequiredFildsArr = (method: string):Array => { case "rotatecaptcha": requiredFieldsArr = rotateRequiredFields break; + case "keycaptcha": + requiredFieldsArr = keycaptchaRequiredFields + break; } return requiredFieldsArr } From cab1fd4060c689795447515964ccb7611da25ce3 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Mon, 28 Oct 2024 16:37:21 +0400 Subject: [PATCH 10/19] Updated KeyKaptcha parameter names --- README.md | 12 ++++++------ examples/keyCaptcha.js | 8 ++++---- src/structs/2captcha.ts | 29 +++++++++++++++-------------- src/utils/renameParams.ts | 9 ++++++++- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index f6d4353..568c7e6 100644 --- a/README.md +++ b/README.md @@ -571,16 +571,16 @@ Token-based method to solve KeyCaptcha. ```js solver.keyCaptcha({ pageurl: "https://2captcha.com/demo/keycaptcha", - s_s_c_user_id: '184015', - s_s_c_session_id: '0917788cad24ad3a69813c4fcd556061', - s_s_c_web_server_sign: '02f7f9669f1269595c4c69bcd4a3c52e', - s_s_c_web_server_sign2: 'd888700f6f324ec0f32b44c32c50bde1' + userId: '184015', + sessionId: '0917788cad24ad3a69813c4fcd556061', + webServerSign: '02f7f9669f1269595c4c69bcd4a3c52e', + webServerSign2: 'd888700f6f324ec0f32b44c32c50bde1' }) .then((res) => { - console.log(res); +console.log(res); }) .catch((err) => { - console.log(err); +console.log(err); }) ``` diff --git a/examples/keyCaptcha.js b/examples/keyCaptcha.js index b4dfb55..f91535d 100644 --- a/examples/keyCaptcha.js +++ b/examples/keyCaptcha.js @@ -5,10 +5,10 @@ const solver = new TwoCaptcha.Solver(APIKEY); solver.keyCaptcha({ pageurl: "https://2captcha.com/demo/keycaptcha", - s_s_c_user_id: '184015', - s_s_c_session_id: '0917788cad24ad3a69813c4fcd556061', - s_s_c_web_server_sign: '02f7f9669f1269595c4c69bcd4a3c52e', - s_s_c_web_server_sign2: 'd888700f6f324ec0f32b44c32c50bde1' + userId: '184015', + sessionId: '0917788cad24ad3a69813c4fcd556061', + webServerSign: '02f7f9669f1269595c4c69bcd4a3c52e', + webServerSign2: 'd888700f6f324ec0f32b44c32c50bde1' }) .then((res) => { console.log(res); diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index a3c9765..f0053f1 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -256,10 +256,10 @@ export interface paramsRotateCaptcha { export interface paramsKeyCaptcha { pageurl: string, - s_s_c_user_id: string, - s_s_c_session_id: string, - s_s_c_web_server_sign: string, - s_s_c_web_server_sign2: string, + userId: string, + sessionId: string, + webServerSign: string, + webServerSign2: string, pingback?: string, proxy?: string, proxytype?: string @@ -1629,12 +1629,12 @@ public async rotate(params: paramsRotateCaptcha): Promise { * This method can be used to solve a KeyCaptcha. It is mostly used to bypass captchas that use KeyCaptcha technology. * [Read more about KeyCaptcha](https://2captcha.com/2captcha-api#solving_keycaptcha). * -* @param {{ pageurl, s_s_c_user_id, s_s_c_session_id, s_s_c_web_server_sign, s_s_c_web_server_sign2, pingback, proxy, proxytype }} params Parameters for solving KeyCaptcha as an object. +* @param {{ pageurl, userId, sessionId, webServerSign, webServerSign2, pingback, proxy, proxytype }} params Parameters for solving KeyCaptcha as an object. * @param {string} params.pageurl The URL where the captcha is located. -* @param {string} params.s_s_c_user_id The user ID provided by KeyCaptcha. -* @param {string} params.s_s_c_session_id The session ID provided by KeyCaptcha. -* @param {string} params.s_s_c_web_server_sign The web server sign provided by KeyCaptcha. -* @param {string} params.s_s_c_web_server_sign2 The second web server sign provided by KeyCaptcha. +* @param {string} params.userId Value of `s_s_c_user_id` parameter you found on page. +* @param {string} params.sessionId Value of `s_s_c_session_id` parameter you found on page. +* @param {string} params.webServerSign Value of `s_s_c_web_server_sign` parameter you found on page. +* @param {string} params.webServerSign2 Value of `s_s_c_web_server_sign2` parameter you found on page. * @param {string} [params.pingback] Optional param. URL for pingback (callback) response when captcha is solved. * @param {string} [params.proxy] Optional param. Proxy to use while solving the captcha. Format: `login:password@123.123.123.123:3128`. * @param {string} [params.proxytype] Optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. @@ -1644,11 +1644,11 @@ public async rotate(params: paramsRotateCaptcha): Promise { * * @example * solver.keyCaptcha({ -* pageurl: "https://example.com/captcha", -* s_s_c_user_id: "12345", -* s_s_c_session_id: "session123", -* s_s_c_web_server_sign: "sign123", -* s_s_c_web_server_sign2: "sign456" +* pageurl: "https://2captcha.com/demo/keycaptcha", +* userId: "184015", +* sessionId: "11975dc265ce9174a54edb1619af15b7", +* webServerSign: "73ef77fd3cf0ce02947d9088bdc8412a", +* webServerSign2: "93836d9e7007f38f072ce07d89bb7e2b" * }) * .then((res) => { * console.log(res); @@ -1658,6 +1658,7 @@ public async rotate(params: paramsRotateCaptcha): Promise { * }) */ public async keyCaptcha(params: paramsKeyCaptcha): Promise { + params = await renameParams(params) checkCaptchaParams(params, "keycaptcha") const payload = { diff --git a/src/utils/renameParams.ts b/src/utils/renameParams.ts index 6682241..578986f 100644 --- a/src/utils/renameParams.ts +++ b/src/utils/renameParams.ts @@ -15,13 +15,20 @@ export default function renameParams(params: any) { * Captcha parameters that need to be renamed before sent to the API. */ const replaceParams: any = { + // Grid "cols" : "recaptchacols", "rows" : "recaptcharows", "minClicks" : "min_clicks", "maxClicks" : "max_clicks", "canSkip" : "can_no_answer", "previousId" : "previousID", - "imgType" : "img_type" + "imgType" : "img_type", + + // KeyKaptcha + "userId" : "s_s_c_user_id", + "sessionId":"s_s_c_session_id", + "webServerSign":"s_s_c_web_server_sign", + "webServerSign2":"s_s_c_web_server_sign2", } for(let key in params) { From db71eff07d236d89f76968fd90581ca9f19f3f1a Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Mon, 28 Oct 2024 16:42:05 +0400 Subject: [PATCH 11/19] typo --- src/utils/renameParams.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/renameParams.ts b/src/utils/renameParams.ts index 578986f..189c5b9 100644 --- a/src/utils/renameParams.ts +++ b/src/utils/renameParams.ts @@ -24,7 +24,7 @@ export default function renameParams(params: any) { "previousId" : "previousID", "imgType" : "img_type", - // KeyKaptcha + // KeyCaptcha "userId" : "s_s_c_user_id", "sessionId":"s_s_c_session_id", "webServerSign":"s_s_c_web_server_sign", From 6c8626d00642327d15738bc06dc6fba486dffb18 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Tue, 29 Oct 2024 13:21:15 +0400 Subject: [PATCH 12/19] Add Cutcaptcha method --- README.md | 21 ++++++++++ examples/cutcaptcha.js | 16 ++++++++ src/structs/2captcha.ts | 73 ++++++++++++++++++++++----------- src/utils/checkCaptchaParams.ts | 6 ++- src/utils/renameParams.ts | 4 ++ 5 files changed, 94 insertions(+), 26 deletions(-) create mode 100644 examples/cutcaptcha.js diff --git a/README.md b/README.md index 568c7e6..5691e33 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Canvas](#canvas) - [Rotate](#rotate) - [KeyCaptcha](#keycaptcha) + - [Cutcaptcha](#cutcaptcha) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -576,6 +577,26 @@ solver.keyCaptcha({ webServerSign: '02f7f9669f1269595c4c69bcd4a3c52e', webServerSign2: 'd888700f6f324ec0f32b44c32c50bde1' }) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) +``` + +### Cutcaptcha + +[API method description.](https://2captcha.com/2captcha-api#cutcaptcha) + +Use this method to solve Cutcaptcha. Returns the response in JSON. + +```js +solver.cutCaptcha({ + pageurl: "https://mysite.com/page/with/cutcaptcha", + misery_key: "098e6a849af406142e3150dbf4e6d0538db2b51f", + api_key: "SAs61IAI", +}) .then((res) => { console.log(res); }) diff --git a/examples/cutcaptcha.js b/examples/cutcaptcha.js new file mode 100644 index 0000000..c7aae38 --- /dev/null +++ b/examples/cutcaptcha.js @@ -0,0 +1,16 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); + +solver.cutCaptcha({ + pageurl: "https://mysite.com/page/with/cutcaptcha", + miseryKey: "098e6a849af406142e3150dbf4e6d0538db2b51f", + apiKey: "SAs61IAI", +}) +.then((res) => { +console.log(res); +}) +.catch((err) => { +console.log(err); +}) \ No newline at end of file diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index f0053f1..7020efd 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -208,6 +208,15 @@ export interface paramsMTCaptcha { proxytype?: string, } +export interface paramsCutcaptcha { + pageurl: string, + miseryKey: string, + apiKey: string, + pingback?: string, + proxy?: string, + proxytype?: string +} + export interface friendlyCaptcha { pageurl: string, sitekey: string, @@ -1234,37 +1243,51 @@ public async mtCaptcha(params: paramsMTCaptcha): Promise { } /** - * ### Solves Cutcaptcha - * - * @param {{ pageurl, sitekey, userAgent, pingback, proxy, proxytype}} params Parameters MTCaptcha as an object. - * @param {string} params.pageurl Full `URL` of the page where you see the captcha. - * @param {string} params.sitekey TThe value of `sitekey` parameter found on the page. - * @param {string} params.pingback URL for pingback (callback) response that will be sent when captcha is solved. URL should be registered on the server. [More info here](https://2captcha.com/2captcha-api#pingback). - * @param {string} params.proxy Format: `login:password@123.123.123.123:3128` You can find more info about proxies [here](https://2captcha.com/2captcha-api#proxies). - * @param {string} params.proxytype Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. - * - * @example - * solver.cutCaptcha({ - * pageurl: "https://service.mtcaptcha.com/mtcv1/demo/index.html", - * sitekey: "MTPublic-DemoKey9M" - * }) - * .then((res) => { - * console.log(res); - * }) - * .catch((err) => { - * console.log(err); - * }) - */ -public async cutCaptcha(params: paramsMTCaptcha): Promise { - checkCaptchaParams(params, "mt_captcha") + * ### Solves a Cutcaptcha. + * + * Use this method to solve Cutcaptcha. Returns the response in JSON. + * [Read more about Cutcaptcha](https://2captcha.com/2captcha-api#Cutcaptcha). + * + * @param {{ pageurl, miseryKey, apiKey, pingback, proxy, proxytype }} params Parameters for solving Cutcaptcha as an object. + * @param {string} params.pageurl The URL where the captcha is located. + * @param {string} params.miseryKey The value of `CUTCAPTCHA_MISERY_KEY` variable defined on page. + * @param {string} params.apiKey The value of `data-apikey` attribute of iframe's body. Also the name of javascript file included on the page + * @param {string} [params.pingback] Optional param. URL for pingback (callback) response when captcha is solved. + * @param {string} [params.proxy] Optional param. Proxy to use while solving the captcha. Format: `login:password@123.123.123.123:3128`. + * @param {string} [params.proxytype] Optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. + * + * @returns {Promise} The result from the solve. + * @throws APIError + * + * @example + * solver.cutCaptcha({ + * pageurl: "https://mysite.com/page/with/cutcaptcha", + * miseryKey: "098e6a849af406142e3150dbf4e6d0538db2b51f", + * apiKey: "SAs61IAI", + * }) + * .then((res) => { + * console.log(res); + * }) + * .catch((err) => { + * console.log(err); + * }) + */ +public async cutCaptcha(params: paramsCutcaptcha): Promise { + params = renameParams(params) + checkCaptchaParams(params, "cutcaptcha") const payload = { ...params, - method: "mt_captcha", + method: "cutcaptcha", ...this.defaultPayload, } - const response = await fetch(this.in + utils.objectToURI(payload)) + const URL = this.in + const response = await fetch(URL, { + body: JSON.stringify(payload), + method: "post", + headers: {'Content-Type': 'application/json'} + }) const result = await response.text() let data; diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index c2e253c..2e45478 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,6 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha', 'cutcaptcha'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -25,6 +25,7 @@ const textCaptchaRequiredFields = ['textcaptcha'] const canvasRequiredFields = ['body'] // and textinstructions or imginstructions const rotateRequiredFields = ['body'] const keycaptchaRequiredFields = ['pageurl', 's_s_c_user_id', 's_s_c_session_id', 's_s_c_web_server_sign', 's_s_c_web_server_sign2'] +const cutcaptchaRequiredFields = ['pageurl', 'misery_key', 'api_key'] /** * Getting required arguments for a captcha. @@ -99,6 +100,9 @@ const getRequiredFildsArr = (method: string):Array => { case "keycaptcha": requiredFieldsArr = keycaptchaRequiredFields break; + case "cutcaptcha": + requiredFieldsArr = cutcaptchaRequiredFields + break; } return requiredFieldsArr } diff --git a/src/utils/renameParams.ts b/src/utils/renameParams.ts index 189c5b9..2d6274c 100644 --- a/src/utils/renameParams.ts +++ b/src/utils/renameParams.ts @@ -29,6 +29,10 @@ export default function renameParams(params: any) { "sessionId":"s_s_c_session_id", "webServerSign":"s_s_c_web_server_sign", "webServerSign2":"s_s_c_web_server_sign2", + + // Cutcaptcha + "miseryKey":"misery_key", + "apiKey":"api_key", } for(let key in params) { From 7e48fcbf2652fcf49e3a1f4c525caec9c978581b Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Tue, 29 Oct 2024 14:09:08 +0400 Subject: [PATCH 13/19] Update description for checkCaptchaParams --- src/utils/checkCaptchaParams.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index 2e45478..48f6961 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -108,6 +108,14 @@ const getRequiredFildsArr = (method: string):Array => { } /** + * ### Captcha Required Parameters Check. + * + * Checking required captcha parameters before sending. + * This function checks for required fields in the provided captcha parameters. + * Throws an error if the specified method is not supported or if required fields are missing. + * + * Note: The `checkCaptchaParams()` function should be called after `renameParams()`, if function `renameParams()` is used. + * * @param { Object } params Captcha parameters that need to be checked. * @returns true | false | Error * @example From 60ee9e712d628fdccafc6af2725a568437035d18 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Tue, 29 Oct 2024 16:53:10 +0400 Subject: [PATCH 14/19] Add Tencent method --- README.md | 20 ++++++++++ examples/tencent.js | 15 ++++++++ src/structs/2captcha.ts | 68 +++++++++++++++++++++++++++++++++ src/utils/checkCaptchaParams.ts | 6 ++- src/utils/renameParams.ts | 3 ++ 5 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 examples/tencent.js diff --git a/README.md b/README.md index 5691e33..697c384 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Rotate](#rotate) - [KeyCaptcha](#keycaptcha) - [Cutcaptcha](#cutcaptcha) + - [Tencent](#tencent) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -605,6 +606,25 @@ console.log(err); }) ``` +### Tencent + +[API method description.](https://2captcha.com/2captcha-api#tencent) + +Use this method to solve Tencent captcha. Returns the response in JSON. + +```js +solver.tencent({ + pageurl: "https://mysite.com/page/with/tencent", + appId: "189956587" +}) +.then((res) => { +console.log(res); +}) +.catch((err) => { +console.log(err); +}) +``` + ## Other methods ### goodReport diff --git a/examples/tencent.js b/examples/tencent.js new file mode 100644 index 0000000..e1557a1 --- /dev/null +++ b/examples/tencent.js @@ -0,0 +1,15 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); + +solver.tencent({ + pageurl: "https://mysite.com/page/with/tencent", + appId: "189956587" +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) \ No newline at end of file diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index 7020efd..eec2327 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -274,6 +274,14 @@ export interface paramsKeyCaptcha { proxytype?: string } +export interface paramsTencent { + pageurl: string, + appId: string, + pingback?: string, + proxy?: string, + proxytype?: string +} + /** * An object containing properties of the captcha solution. * @typedef {Object} CaptchaAnswer @@ -1712,6 +1720,66 @@ public async keyCaptcha(params: paramsKeyCaptcha): Promise { } } +/** +* ### Solves a Tencent. +* +* Use this method to solve Tencent captcha. Returns a token. +* [Read more about Tencent](https://2captcha.com/2captcha-api#tencent). +* +* @param {{ pageurl, appId, pingback, proxy, proxytype }} params Parameters for solving Tencent as an object. +* @param {string} params.pageurl The URL where the captcha is located. +* @param {string} params.appId The value of `appId` parameter in the website source code. +* @param {string} [params.pingback] Optional param. URL for pingback (callback) response when captcha is solved. +* @param {string} [params.proxy] Optional param. Proxy to use while solving the captcha. Format: `login:password@123.123.123.123:3128`. +* @param {string} [params.proxytype] Optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. +* +* @returns {Promise} The result from the solve. +* @throws APIError +* +* @example +* solver.tencent({ +* pageurl: "https://mysite.com/page/with/tencent", +* appId: "189956587" +* }) +* .then((res) => { +* console.log(res); +* }) +* .catch((err) => { +* console.log(err); +* }) +*/ +public async tencent(params: paramsTencent): Promise { + params = await renameParams(params) + checkCaptchaParams(params, "tencent") + + const payload = { + ...params, + method: "tencent", + ...this.defaultPayload, + } + + const URL = this.in + const response = await fetch(URL, { + body: JSON.stringify(payload), + method: "post", + headers: {'Content-Type': 'application/json'} + }) + const result = await response.text() + + let data; + try { + data = JSON.parse(result) + } catch { + throw new APIError(result) + } + + if (data.status == 1) { + return this.pollResponse(data.request) + } else { + throw new APIError(data.request) + } +} + /** * Reports a captcha as correctly solved. * diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index 48f6961..a260e42 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,6 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha', 'cutcaptcha'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha', 'cutcaptcha', 'tencent'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -26,6 +26,7 @@ const canvasRequiredFields = ['body'] // and textinstructions or imginstruc const rotateRequiredFields = ['body'] const keycaptchaRequiredFields = ['pageurl', 's_s_c_user_id', 's_s_c_session_id', 's_s_c_web_server_sign', 's_s_c_web_server_sign2'] const cutcaptchaRequiredFields = ['pageurl', 'misery_key', 'api_key'] +const tencentRequiredFields = ['pageurl', 'app_id'] /** * Getting required arguments for a captcha. @@ -103,6 +104,9 @@ const getRequiredFildsArr = (method: string):Array => { case "cutcaptcha": requiredFieldsArr = cutcaptchaRequiredFields break; + case "tencent": + requiredFieldsArr = tencentRequiredFields + break; } return requiredFieldsArr } diff --git a/src/utils/renameParams.ts b/src/utils/renameParams.ts index 2d6274c..b0883a3 100644 --- a/src/utils/renameParams.ts +++ b/src/utils/renameParams.ts @@ -33,6 +33,9 @@ export default function renameParams(params: any) { // Cutcaptcha "miseryKey":"misery_key", "apiKey":"api_key", + + // Tencent + "appId": "app_id", } for(let key in params) { From a7086f732f0d879fd99a49892026c7f1df2ca670 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Tue, 29 Oct 2024 19:32:00 +0400 Subject: [PATCH 15/19] Add atbCaptcha method --- README.md | 21 ++++++++++ examples/atbcaptcha.js | 16 ++++++++ src/structs/2captcha.ts | 71 +++++++++++++++++++++++++++++++++ src/utils/checkCaptchaParams.ts | 8 +++- src/utils/renameParams.ts | 3 ++ 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 examples/atbcaptcha.js diff --git a/README.md b/README.md index 697c384..e725494 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [KeyCaptcha](#keycaptcha) - [Cutcaptcha](#cutcaptcha) - [Tencent](#tencent) + - [atbCAPTCHA](#atbcaptcha) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -625,6 +626,26 @@ console.log(err); }) ``` +### atbCAPTCHA + +[API method description.](https://2captcha.com/2captcha-api#atb-captcha) + +Use this method to solve atbCAPTCHA challenge. Returns a token to bypass the captcha. + +```js +solver.atbCaptcha({ + pageurl: "https://mysite.com/page/with/atbCAPTCHA", + appId: "af25e409b33d722a95e56a230ff8771c", + apiServer: "https://cap.aisecurius.com" +}) +.then((res) => { +console.log(res); +}) +.catch((err) => { +console.log(err); +}) +``` + ## Other methods ### goodReport diff --git a/examples/atbcaptcha.js b/examples/atbcaptcha.js new file mode 100644 index 0000000..fc8a967 --- /dev/null +++ b/examples/atbcaptcha.js @@ -0,0 +1,16 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); + +solver.atbCaptcha({ + pageurl: "https://mysite.com/page/with/atbCAPTCHA", + appId: "af25e409b33d722a95e56a230ff8771c", + apiServer: "https://cap.aisecurius.com" +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) \ No newline at end of file diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index eec2327..cce8d0b 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -282,6 +282,15 @@ export interface paramsTencent { proxytype?: string } +export interface paramsAtbCaptcha{ + pageurl: string, + appId: string, + apiServer: string, + pingback?: string, + proxy?: string, + proxytype?: string +} + /** * An object containing properties of the captcha solution. * @typedef {Object} CaptchaAnswer @@ -1780,6 +1789,68 @@ public async tencent(params: paramsTencent): Promise { } } +/** +* ### Solves a atbCAPTCHA. +* +* Use this method to solve atbCAPTCHA captcha. Returns a token. +* [Read more about atbCAPTCHA](https://2captcha.com/2captcha-api#atb-captcha). +* +* @param {{ pageurl, appId, apiServer, pingback, proxy, proxytype }} params Parameters for solving atbCAPTCHA as an object. +* @param {string} params.pageurl The URL where the captcha is located. +* @param {string} params.appId The value of `appId` parameter in the website source code. +* @param {string} params.apiServer The value of `apiServer` parameter in the website source code. +* @param {string} [params.pingback] Optional param. URL for pingback (callback) response when captcha is solved. +* @param {string} [params.proxy] Optional param. Proxy to use while solving the captcha. Format: `login:password@123.123.123.123:3128`. +* @param {string} [params.proxytype] Optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. +* +* @returns {Promise} The result from the solve. +* @throws APIError +* +* @example +* solver.atbCaptcha({ +* pageurl: "https://mysite.com/page/with/tencent", +* appId: "af25e409b33d722a95e56a230ff8771c", + apiServer: "https://cap.aisecurius.com" +* }) +* .then((res) => { +* console.log(res); +* }) +* .catch((err) => { +* console.log(err); +* }) +*/ +public async atbCaptcha(params: paramsAtbCaptcha): Promise { + params = await renameParams(params) + checkCaptchaParams(params, "atb_captcha") + + const payload = { + ...params, + method: "atb_captcha", + ...this.defaultPayload, + } + + const URL = this.in + const response = await fetch(URL, { + body: JSON.stringify(payload), + method: "post", + headers: {'Content-Type': 'application/json'} + }) + const result = await response.text() + + let data; + try { + data = JSON.parse(result) + } catch { + throw new APIError(result) + } + + if (data.status == 1) { + return this.pollResponse(data.request) + } else { + throw new APIError(data.request) + } +} + /** * Reports a captcha as correctly solved. * diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index a260e42..f4374e7 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,6 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha', 'cutcaptcha', 'tencent'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha', 'cutcaptcha', 'tencent', 'atb_captcha'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -26,7 +26,8 @@ const canvasRequiredFields = ['body'] // and textinstructions or imginstruc const rotateRequiredFields = ['body'] const keycaptchaRequiredFields = ['pageurl', 's_s_c_user_id', 's_s_c_session_id', 's_s_c_web_server_sign', 's_s_c_web_server_sign2'] const cutcaptchaRequiredFields = ['pageurl', 'misery_key', 'api_key'] -const tencentRequiredFields = ['pageurl', 'app_id'] +const tencentRequiredFields = ['pageurl', 'app_id'] +const atbCaptchaRequiredFields = ['pageurl', 'app_id', 'api_server'] /** * Getting required arguments for a captcha. @@ -107,6 +108,9 @@ const getRequiredFildsArr = (method: string):Array => { case "tencent": requiredFieldsArr = tencentRequiredFields break; + case "atb_captcha": + requiredFieldsArr = atbCaptchaRequiredFields + break; } return requiredFieldsArr } diff --git a/src/utils/renameParams.ts b/src/utils/renameParams.ts index b0883a3..d3953e4 100644 --- a/src/utils/renameParams.ts +++ b/src/utils/renameParams.ts @@ -36,6 +36,9 @@ export default function renameParams(params: any) { // Tencent "appId": "app_id", + + // atbCAPTCHA + "apiServer": "api_server", } for(let key in params) { From b17e7ad5781ac1f54794f4f30e4e902695a34c73 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Tue, 29 Oct 2024 21:29:42 +0400 Subject: [PATCH 16/19] Add Audio method --- README.md | 20 ++++++++++ examples/audio.js | 17 +++++++++ examples/media/example.mp3 | Bin 0 -> 34283 bytes src/structs/2captcha.ts | 63 ++++++++++++++++++++++++++++++++ src/utils/checkCaptchaParams.ts | 7 +++- 5 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 examples/audio.js create mode 100644 examples/media/example.mp3 diff --git a/README.md b/README.md index e725494..6a42b50 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Cutcaptcha](#cutcaptcha) - [Tencent](#tencent) - [atbCAPTCHA](#atbcaptcha) + - [Audio Captcha](#audio-captcha) - [Other methods](#other-methods) - [goodReport](#goodreport) - [badReport](#badreport) @@ -646,6 +647,25 @@ console.log(err); }) ``` +### Audio Captcha + +[API method description.](https://2captcha.com/2captcha-api#audio-recognition) + +Use the following method to bypass an audio captcha (`mp3` formats only). You must provide the language as `lang = 'en'`. Supported languages are "en", "ru", "de", "el", "pt", "fr". + +```js +solver.audio({ + body: "SUQzBAAAAAAAHFRTU0UAAAA...", + lang: "en" +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) +``` + ## Other methods ### goodReport diff --git a/examples/audio.js b/examples/audio.js new file mode 100644 index 0000000..bb1ee80 --- /dev/null +++ b/examples/audio.js @@ -0,0 +1,17 @@ +const TwoCaptcha = require("../dist/index.js"); +require('dotenv').config(); +const APIKEY = process.env.APIKEY +const solver = new TwoCaptcha.Solver(APIKEY); +const fs = require('fs') +const audioCaptchaBase64 = fs.readFileSync("./media/example.mp3", "base64") + +solver.audio({ + body: audioCaptchaBase64, + lang: 'en' +}) +.then((res) => { + console.log(res); +}) +.catch((err) => { + console.log(err); +}) \ No newline at end of file diff --git a/examples/media/example.mp3 b/examples/media/example.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..c063a6a97e18e512eba3bde80d8db9f9c66bd0ec GIT binary patch literal 34283 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 F{|6x@9)17- literal 0 HcmV?d00001 diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index cce8d0b..e0944a1 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -291,6 +291,12 @@ export interface paramsAtbCaptcha{ proxytype?: string } +export interface paramsAudioCaptcha { + body: string, + lang: string, + pingback?: string, +} + /** * An object containing properties of the captcha solution. * @typedef {Object} CaptchaAnswer @@ -1851,6 +1857,63 @@ public async atbCaptcha(params: paramsAtbCaptcha): Promise { } } + +/** + * ### Method for solving Audio captcha. + * + * Use the following method to bypass an audio captcha (`mp3` formats only). You must provide the language as `lang = 'en'`. Supported languages are "en", "ru", "de", "el", "pt", "fr". + * [Read more about audio captcha parameters](https://2captcha.com/2captcha-api#audio). + * + * @param {{ body, lang, pingback }} params Object containing parameters for the audio captcha. + * @param {string} params.body Base64 encoded audio file in `mp3` format. Max file size: 1 MB. + * @param {string} params.lang The language of audio record. Supported languages are: "en", "ru", "de", "el", "pt", "fr". + * @param {string} [params.pingback] URL for pingback response once captcha is solved. + * + * @returns {Promise} The result from solving the audio captcha. + * @throws APIError + * @example + * solver.audio({ + * body: "SUQzBAAAAAAAHFRTU0UAAAA...", + * lang: "en" + * }) + * .then((res) => { + * console.log(res); + * }) + * .catch((err) => { + * console.log(err); + * }) + */ +public async audio(params: paramsAudioCaptcha): Promise { + checkCaptchaParams(params, "audio") + + const payload = { + ...params, + method: "audio", + ...this.defaultPayload + } + + const response = await fetch(this.in, { + method: 'post', + body: JSON.stringify(payload), + headers: {'Content-Type': 'application/json'} + }) + + const result = await response.text() + + let data; + try { + data = JSON.parse(result) + } catch { + throw new APIError(result) + } + + if (data.status == 1) { + return this.pollResponse(data.request) + } else { + throw new APIError(data.request) + } +} + /** * Reports a captcha as correctly solved. * diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index f4374e7..7f5c0c2 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -1,6 +1,7 @@ // Captcha methods for which parameter checking is available const supportedMethods = ["userrecaptcha", "hcaptcha", "geetest", "geetest_v4","yandex","funcaptcha","lemin","amazon_waf", -"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha', 'cutcaptcha', 'tencent', 'atb_captcha'] +"turnstile", "base64", "capy","datadome", "cybersiara", "mt_captcha", "bounding_box", 'friendly_captcha', 'grid', + 'textcaptcha', 'canvas', 'rotatecaptcha', 'keycaptcha', 'cutcaptcha', 'tencent', 'atb_captcha', 'audio'] // Names of required fields that must be contained in the parameters captcha const recaptchaRequiredFields = ['pageurl','googlekey'] @@ -28,6 +29,7 @@ const keycaptchaRequiredFields = ['pageurl', 's_s_c_user_id', 's_s_c_session_id const cutcaptchaRequiredFields = ['pageurl', 'misery_key', 'api_key'] const tencentRequiredFields = ['pageurl', 'app_id'] const atbCaptchaRequiredFields = ['pageurl', 'app_id', 'api_server'] +const audioRequiredFields = ['body', 'lang'] /** * Getting required arguments for a captcha. @@ -111,6 +113,9 @@ const getRequiredFildsArr = (method: string):Array => { case "atb_captcha": requiredFieldsArr = atbCaptchaRequiredFields break; + case "audio": + requiredFieldsArr = audioRequiredFields + break; } return requiredFieldsArr } From d2c69eaae482999c8f8a208f1fa7efc4e546c5d6 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Wed, 30 Oct 2024 16:14:25 +0400 Subject: [PATCH 17/19] Update README.md --- README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6a42b50..08bde41 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,15 @@ # JavaScript module for 2Captcha API (captcha solver) -The easiest way to quickly integrate the [2Captcha](https://2captcha.com/) captcha-solving service into your code and automate the solving of any type of captcha. -Examples of API requests for different captcha types are available on the [JavaScript captcha solver](https://2captcha.com/lang/javascript) page. +The easiest way to quickly integrate the [2Captcha] captcha-solving service into your code and automate the solving of any type of captcha. +Examples of API requests for different captcha types are available on the [JavaScript captcha solver] page. - [JavaScript module for 2Captcha API (captcha solver)](#javascript-module-for-2captcha-api-captcha-solver) - [Installation](#installation) - [Configuration](#configuration) - [TwoCaptcha instance options](#twocaptcha-instance-options) - [Solve captcha](#solve-captcha) - - [Image captchas](#image-captcha) + - [Image Сaptcha](#image-captcha) - [reCAPTCHA v2](#recaptcha-v2) - [reCAPTCHA v3](#recaptcha-v3) - [hCaptcha](#hcaptcha) @@ -51,7 +51,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Proxies](#proxies) - [Examples](#examples) - [Examples using Puppeteer](#examples-using-puppeteer) - - [Useful articles](#useful-articles) +- [Useful articles](#useful-articles) - [Get in touch](#get-in-touch) - [Join the team 👪](#join-the-team-) - [License](#license) @@ -119,7 +119,6 @@ Below you can find basic examples for every captcha type, check out the code bel To bypass a normal captcha (distorted text on an image) use the following method. This method can also be used to recognize any text in an image. ```js -// Read from a file as base64 text const imageBase64 = fs.readFileSync("./examples/media/imageCaptcha_6e584.png", "base64") solver.imageCaptcha({ @@ -129,7 +128,6 @@ solver.imageCaptcha({ max_len: 5 }) .then((res) => { - // Logs the image text console.log(res); }) .catch((err) => { @@ -726,6 +724,7 @@ At the moment we have implemented examples of bypassing Cloudflare Challenge pag Links: - [Cloudflare Bypassing Demo using Puppeteer](https://github.com/2captcha/cloudflare-demo) - [Solving reCAPTCHA V2 using Puppeteer and clicks](https://github.com/2captcha/puppeteer-recaptcha-solver-using-clicks) +- [Custom Slider Captcha Demo](https://github.com/2captcha/custom-slider-demo) ## Useful articles @@ -733,8 +732,6 @@ Links: * [Bypassing Cloudflare Challenge with Puppeteer and 2Captcha](https://2captcha.com/blog/bypassing-cloudflare-challenge-with-puppeteer-and-2captcha) * [How to bypass Geetest v4 CAPTCHA](https://2captcha.com/blog/geetest-v4-support) * [Automatic reCAPTCHA V3 resolution - a tutorial for developers and customers](https://2captcha.com/blog/recaptcha-v3-automatic-resolution) -* [Custom Slider Captcha Demo](https://github.com/2captcha/custom-slider-demo) -* [Cloudflare Challenge page bypass code example](https://github.com/2captcha/cloudflare-demo) ## Get in touch @@ -756,6 +753,8 @@ The code in this repository is licensed under the MIT License. See the [LICENSE] The graphics and trademarks included in this repository are not covered by the MIT License. Please contact support for permissions regarding the use of these materials. +[2Captcha]: https://2captcha.com/ +[JavaScript captcha solver]: https://2captcha.com/lang/javascript [post options]: https://2captcha.com/2captcha-api#normal_post [list of supported languages]: https://2captcha.com/2captcha-api#language [Buy residential proxies]: https://2captcha.com/proxy/residential-proxies From 5a2ec5cbc208548d6e59260e5147a29029a73143 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Wed, 30 Oct 2024 19:01:04 +0400 Subject: [PATCH 18/19] Refactor --- README.md | 2 +- examples/{recaptcha.js => recaptcha_v2.js} | 0 examples/tencent.js | 2 +- src/structs/2captcha.ts | 108 ++++++++------------- src/utils/checkCaptchaParams.ts | 8 +- 5 files changed, 49 insertions(+), 71 deletions(-) rename examples/{recaptcha.js => recaptcha_v2.js} (100%) diff --git a/README.md b/README.md index 08bde41..5b6a629 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Examples of API requests for different captcha types are available on the [JavaS - [Configuration](#configuration) - [TwoCaptcha instance options](#twocaptcha-instance-options) - [Solve captcha](#solve-captcha) - - [Image Сaptcha](#image-captcha) + - [Image Captcha](#image-captcha) - [reCAPTCHA v2](#recaptcha-v2) - [reCAPTCHA v3](#recaptcha-v3) - [hCaptcha](#hcaptcha) diff --git a/examples/recaptcha.js b/examples/recaptcha_v2.js similarity index 100% rename from examples/recaptcha.js rename to examples/recaptcha_v2.js diff --git a/examples/tencent.js b/examples/tencent.js index e1557a1..d077de4 100644 --- a/examples/tencent.js +++ b/examples/tencent.js @@ -5,7 +5,7 @@ const solver = new TwoCaptcha.Solver(APIKEY); solver.tencent({ pageurl: "https://mysite.com/page/with/tencent", - appId: "189956587" + appId: "189956587" }) .then((res) => { console.log(res); diff --git a/src/structs/2captcha.ts b/src/structs/2captcha.ts index e0944a1..7802974 100644 --- a/src/structs/2captcha.ts +++ b/src/structs/2captcha.ts @@ -43,7 +43,6 @@ export interface paramsHCaptcha { domain?: string } -// FixMe:data[key] - how to send this parameter export interface paramsFunCaptcha { publickey: string, pageurl: string, @@ -84,18 +83,6 @@ export interface paramsGeetest { userAgent?: string } -/** - * Interface for yandexSmart captcha - * - * @typedef {object} yandexSmart - * @property {string} pageurl URL of the page where the captcha is located - * @property {string} sitekey The `sitekey` value you found on the captcha page - * @property {string} pingback - * @property {string} proxy Format: `login:password@123.123.123.123:3128`. You can find more info about proxies [here](https://2captcha.com/2captcha-api#proxies). - * @property {string} proxytype Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. - * @property {string} userAgent Your `userAgent` that will be passed to our worker and used to solve the captcha. - * - */ export interface yandexSmart { pageurl: string, sitekey: string, @@ -105,18 +92,6 @@ export interface yandexSmart { userAgent?: string } -/** - * Interface for GeeTest V4 captcha - * - * @typedef {object} paramsGeeTestV4 - * @property {string} pageurl Required parameter. URL of the page where the captcha is located - * @property {string} captcha_id Required parameter. Value of `captcha_id` parameter you found on target website. - * @property {string} pingback An optional param. [More info here](https://2captcha.com/2captcha-api#pingback). - * @property {string} proxy An optional param. Format: `login:password@123.123.123.123:3128` - * @property {string} proxytype An optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. - * @property {string} userAgent An optional param. Your `userAgent` that will be passed to our worker and used to solve the captcha. - * - */ export interface paramsGeeTestV4 { pageurl: string, captcha_id: string, @@ -237,8 +212,8 @@ export interface paramsGrid { canvas?: number, rows?: number, cols?: number, - minСlicks?: number, - maxСlicks?: number, + minClicks?: number, + maxClicks?: number, previousId?: string, imgType?: string, textinstructions?: string, @@ -960,7 +935,7 @@ export class Solver { * * [Read more about Cloudflare Turnstile captcha](https://2captcha.com/2captcha-api#turnstile). * - * @param {{ pageurl, sitekey, action, data, pingback, proxy, proxytype}} params The `сloudflareTurnstile` method takes arguments as an object. Thus, the `pageurl`, `sitekey` fields in the passed object are mandatory. + * @param {{ pageurl, sitekey, action, data, pingback, proxy, proxytype}} params The `cloudflareTurnstile` method takes arguments as an object. Thus, the `pageurl`, `sitekey` fields in the passed object are mandatory. * @param {string} params.pageurl Full `URL` of the page where you see the captcha. * @param {string} params.sitekey Is a value of `sitekey` parameter in the page source. * @param {string} params.action Value of optional `action` parameter you found on page. @@ -1009,7 +984,7 @@ export class Solver { /** * ### Solves a Coordinates captcha. * - * @param {{ body, imginstructions, textinstructions, language, lang, pingback }} params parameters Сoordinates Captcha as an object. + * @param {{ body, imginstructions, textinstructions, language, lang, pingback }} params parameters Coordinates Captcha as an object. * @param {string} params.body Base64-encoded captcha image. * @param {string} params.imginstructions Base64-encoded image with instruction for solving captcha. * @param {string} params.textinstructions Text will be shown to worker to help him to solve the captcha correctly. For example: click on all objects in red color. @@ -1266,35 +1241,35 @@ public async mtCaptcha(params: paramsMTCaptcha): Promise { } /** - * ### Solves a Cutcaptcha. - * - * Use this method to solve Cutcaptcha. Returns the response in JSON. - * [Read more about Cutcaptcha](https://2captcha.com/2captcha-api#Cutcaptcha). - * - * @param {{ pageurl, miseryKey, apiKey, pingback, proxy, proxytype }} params Parameters for solving Cutcaptcha as an object. - * @param {string} params.pageurl The URL where the captcha is located. - * @param {string} params.miseryKey The value of `CUTCAPTCHA_MISERY_KEY` variable defined on page. - * @param {string} params.apiKey The value of `data-apikey` attribute of iframe's body. Also the name of javascript file included on the page - * @param {string} [params.pingback] Optional param. URL for pingback (callback) response when captcha is solved. - * @param {string} [params.proxy] Optional param. Proxy to use while solving the captcha. Format: `login:password@123.123.123.123:3128`. - * @param {string} [params.proxytype] Optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. - * - * @returns {Promise} The result from the solve. - * @throws APIError - * - * @example - * solver.cutCaptcha({ - * pageurl: "https://mysite.com/page/with/cutcaptcha", - * miseryKey: "098e6a849af406142e3150dbf4e6d0538db2b51f", - * apiKey: "SAs61IAI", - * }) - * .then((res) => { - * console.log(res); - * }) - * .catch((err) => { - * console.log(err); - * }) - */ + * ### Solves a Cutcaptcha. + * + * Use this method to solve Cutcaptcha. Returns the response in JSON. + * [Read more about Cutcaptcha Method](https://2captcha.com/2captcha-api#cutcaptcha). + * + * @param {{ pageurl, miseryKey, apiKey, pingback, proxy, proxytype }} params Parameters for solving Cutcaptcha as an object. + * @param {string} params.pageurl The URL where the captcha is located. + * @param {string} params.miseryKey The value of `CUTCAPTCHA_MISERY_KEY` variable defined on page. + * @param {string} params.apiKey The value of `data-apikey` attribute of iframe's body. Also the name of javascript file included on the page + * @param {string} [params.pingback] Optional param. URL for pingback (callback) response when captcha is solved. + * @param {string} [params.proxy] Optional param. Proxy to use while solving the captcha. Format: `login:password@123.123.123.123:3128`. + * @param {string} [params.proxytype] Optional param. Type of your proxy: `HTTP`, `HTTPS`, `SOCKS4`, `SOCKS5`. + * + * @returns {Promise} The result from the solve. + * @throws APIError + * + * @example + * solver.cutCaptcha({ + * pageurl: "https://mysite.com/page/with/cutcaptcha", + * miseryKey: "098e6a849af406142e3150dbf4e6d0538db2b51f", + * apiKey: "SAs61IAI", + * }) + * .then((res) => { + * console.log(res); + * }) + * .catch((err) => { + * console.log(err); + * }) + */ public async cutCaptcha(params: paramsCutcaptcha): Promise { params = renameParams(params) checkCaptchaParams(params, "cutcaptcha") @@ -1432,14 +1407,14 @@ public async boundingBox(params: paramsBoundingBox): Promise { * * The method can be used to bypass tasks where a grid is applied to an image and you need to click on grid tiles, like reCAPTCHA or hCaptcha images. * - * @param {{ body, textinstructions, imginstructions, rows, cols, minСlicks, maxСlicks, imgType, previousId, canSkip, lang, pingback}} params Parameters Grid Method as an object. + * @param {{ body, textinstructions, imginstructions, rows, cols, minClicks, maxClicks, imgType, previousId, canSkip, lang, pingback}} params Parameters Grid Method as an object. * @param {string} params.body `Base64`- encoded captcha image. * @param {string} params.textinstructions Text will be shown to worker to help him to select object on the image correctly. For example: "*Select cars in the image*". **Optional parameter**, if the instruction already exists in the form of the `imginstructions`. * @param {string} params.imginstructions Image with instruction for worker to help him to select object on the image correctly. The image must be encoded in `Base64` format. **Optional parameter**, if the instruction already exists in the form of the `textinstructions`. * @param {number} params.rows Number of rows in grid captcha. * @param {number} params.cols Number of columns in grid captcdha. - * @param {number} params.minСlicks The minimum number of tiles that must be selected. Can't be more than `rows` * `cols`. - * @param {number} params.maxСlicks The maximum number of tiles that can be selected on the image. + * @param {number} params.minClicks The minimum number of tiles that must be selected. Can't be more than `rows` * `cols`. + * @param {number} params.maxClicks The maximum number of tiles that can be selected on the image. * @param {string} params.imgType The image will be recognized using Computer Vision. Supported value options: `recaptcha`, `hcaptcha`, `funcaptcha`, `funcaptcha_compare`. [More info here](https://2captcha.com/2captcha-api#grid). * @param {string} params.previousId Id of your previous request with the same captcha challenge. * @param {number} params.canSkip Set the value to `1` only if it's possible that there's no images matching to the instruction. We'll provide a button "No matching images" to worker and you will receive `No_matching_images` as answer. @@ -1497,6 +1472,7 @@ public async grid(params: paramsGrid): Promise { * ### Text Captcha method * * Text Captcha is a type of captcha that is represented as text and doesn't contain images. Usually you have to answer a question to pass the verification. For example: "If tomorrow is Saturday, what day is today?". + * [Read more about Text Captcha Method](https://2captcha.com/2captcha-api#text-captcha). * * @param {{ textcaptcha, lang, pingback}} params Parameters Text Captcha Method as an object. * @param {string} params.textcaptcha Text Captcha is a type of captcha that is represented as text and doesn't contain images. Usually you have to answer a question to pass the verification. @@ -1551,6 +1527,7 @@ public async text(params: paramsTextcaptcha): Promise { * ### Canvas method * * This method can be used to bypass tasks in which you need to circle an object or line in an image. + * [Read more about Canvas Method](https://2captcha.com/2captcha-api#canvas). * * @param {{ body, textinstructions, imginstructions, canSkip, lang, pingback}} params Parameters Canvas as an object. * @param {string} params.body `Base64`- encoded captcha image. @@ -1612,6 +1589,7 @@ public async canvas(params: paramsGrid): Promise { * ### Rotate method * * This method can be used to solve a captcha that asks to rotate an object. It is mostly used to bypass FunCaptcha. Returns the rotation angle. + * [Read more about Rotate Method](https://2captcha.com/2captcha-api#solving_rotatecaptcha). * * @param {{ body, angle, pingback, lang, textinstructions, imginstructions }} params Parameters for solving Rotate Captcha as an object. * @param {string} params.body Base64-encoded image of the captcha that needs to be rotated. @@ -1673,7 +1651,7 @@ public async rotate(params: paramsRotateCaptcha): Promise { * ### Solves a KeyCaptcha. * * This method can be used to solve a KeyCaptcha. It is mostly used to bypass captchas that use KeyCaptcha technology. -* [Read more about KeyCaptcha](https://2captcha.com/2captcha-api#solving_keycaptcha). +* [Read more about KeyCaptcha Method](https://2captcha.com/2captcha-api#solving_keycaptcha). * * @param {{ pageurl, userId, sessionId, webServerSign, webServerSign2, pingback, proxy, proxytype }} params Parameters for solving KeyCaptcha as an object. * @param {string} params.pageurl The URL where the captcha is located. @@ -1739,7 +1717,7 @@ public async keyCaptcha(params: paramsKeyCaptcha): Promise { * ### Solves a Tencent. * * Use this method to solve Tencent captcha. Returns a token. -* [Read more about Tencent](https://2captcha.com/2captcha-api#tencent). +* [Read more about Tencent Method](https://2captcha.com/2captcha-api#tencent). * * @param {{ pageurl, appId, pingback, proxy, proxytype }} params Parameters for solving Tencent as an object. * @param {string} params.pageurl The URL where the captcha is located. @@ -1799,7 +1777,7 @@ public async tencent(params: paramsTencent): Promise { * ### Solves a atbCAPTCHA. * * Use this method to solve atbCAPTCHA captcha. Returns a token. -* [Read more about atbCAPTCHA](https://2captcha.com/2captcha-api#atb-captcha). +* [Read more about atbCAPTCHA Method](https://2captcha.com/2captcha-api#atb-captcha). * * @param {{ pageurl, appId, apiServer, pingback, proxy, proxytype }} params Parameters for solving atbCAPTCHA as an object. * @param {string} params.pageurl The URL where the captcha is located. @@ -1862,7 +1840,7 @@ public async atbCaptcha(params: paramsAtbCaptcha): Promise { * ### Method for solving Audio captcha. * * Use the following method to bypass an audio captcha (`mp3` formats only). You must provide the language as `lang = 'en'`. Supported languages are "en", "ru", "de", "el", "pt", "fr". - * [Read more about audio captcha parameters](https://2captcha.com/2captcha-api#audio). + * [Read more about Audio recognition Method](https://2captcha.com/2captcha-api#audio-recognition). * * @param {{ body, lang, pingback }} params Object containing parameters for the audio captcha. * @param {string} params.body Base64 encoded audio file in `mp3` format. Max file size: 1 MB. diff --git a/src/utils/checkCaptchaParams.ts b/src/utils/checkCaptchaParams.ts index 7f5c0c2..9e63fd7 100644 --- a/src/utils/checkCaptchaParams.ts +++ b/src/utils/checkCaptchaParams.ts @@ -17,8 +17,8 @@ const turnstileRequiredFields = ['pageurl','sitekey'] const base64RequiredFields = ['body'] const capyPuzzleRequiredFields = ['captchakey'] const dataDomeRequiredFields = ['pageurl', 'captcha_url', 'userAgent', 'proxy', 'proxytype'] -const сyberSiARARequiredFields = ['pageurl', 'master_url_id', 'userAgent'] -const mtСaptchaRequiredFields = ['pageurl', 'sitekey'] +const cyberSiARARequiredFields = ['pageurl', 'master_url_id', 'userAgent'] +const mtCaptchaRequiredFields = ['pageurl', 'sitekey'] const boundingBoxRequiredFields = ['image'] // and textinstructions or imginstructions const friendlyCaptchaFields = ['pageurl','sitekey'] const gridRequiredFields = ['body'] // and textinstructions or imginstructions @@ -81,10 +81,10 @@ const getRequiredFildsArr = (method: string):Array => { requiredFieldsArr = dataDomeRequiredFields break; case "cybersiara": - requiredFieldsArr = сyberSiARARequiredFields + requiredFieldsArr = cyberSiARARequiredFields break; case "mt_captcha": - requiredFieldsArr = mtСaptchaRequiredFields + requiredFieldsArr = mtCaptchaRequiredFields break; case "bounding_box": requiredFieldsArr = boundingBoxRequiredFields From 5e69259b3483fc7522c82086c7dcda66be73fe08 Mon Sep 17 00:00:00 2001 From: dzmitry-duboyski Date: Thu, 31 Oct 2024 11:57:42 +0400 Subject: [PATCH 19/19] 1.3.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 68cb8a7..27edb42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@2captcha/captcha-solver", - "version": "1.2.0", + "version": "1.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@2captcha/captcha-solver", - "version": "1.2.0", + "version": "1.3.0", "license": "MIT", "dependencies": { "node-fetch": "^2.6.1" diff --git a/package.json b/package.json index 238284a..c235b40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@2captcha/captcha-solver", - "version": "1.2.0", + "version": "1.3.0", "description": "JavaScript library for easy integration with the API of 2captcha captcha solving service to bypass reCAPTCHA, hCaptcha, funcaptcha, geetest and solve any other captchas.", "main": "dist/index.js", "repository": {