diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 0000000..23ed9a1 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,21 @@ +name: Publish to npm + +on: + push: + branches: + - main + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm ci + - run: npm run build + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..735362e --- /dev/null +++ b/.gitignore @@ -0,0 +1,161 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json +node_modules/ + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +.idea/ \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..2005d12 --- /dev/null +++ b/.npmignore @@ -0,0 +1,16 @@ + +# Files +.yarn.lock +.gitignore +download.jpg +readme.md +jsdoc.json +.env +.idea/ +src/ +node_modules/ +tests/ +tsconfig.json/ +out/ +docs/ +issues/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ebe1bb7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright © 2024 NextCaptcha, https://nextcaptcha.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..41449e8 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# NextCaptcha Node.js SDK + +NextCaptcha is a powerful captcha solving service that supports various types of captchas including reCAPTCHA v2, +reCAPTCHA v2 Enterprise, reCAPTCHA v3, reCAPTCHA Mobile, hCaptcha, hCaptcha Enterprise, and FunCaptcha. With +NextCaptcha, you can easily solve a variety of captcha challenges in your automation scripts and programs. + +This SDK provides a simple and easy-to-use Node.js interface for interacting with the NextCaptcha API. It supports all +available captcha types and offers intuitive methods for solving different types of captchas. + +## Installation + +You can install the NextCaptcha Node.js SDK using npm: + +```shell +npm install nextcaptcha-ts +``` + +## Usage + +To start using the NextCaptcha Node.js SDK, you first need to obtain your API key from the NextCaptcha Dashboard. Then, +you can create a NextCaptcha instance: + +```typescript +import {NextCaptcha} from 'nextcaptcha'; + +const apiKey = 'YOUR_API_KEY'; +const nextCaptcha = new NextCaptcha(apiKey); +``` + +Now, you can use the nextCaptcha object to solve various types of captchas. +Solving reCAPTCHA v2 +To solve reCAPTCHA v2 challenges, use the recaptchaV2 method: + +```typescript +const result = await nextCaptcha.recaptchaV2(websiteURL, websiteKey); +``` + +Solving reCAPTCHA v3 +To solve reCAPTCHA v3 challenges, use the recaptchaV3 method: + +```typescript +const result = await nextCaptcha.recaptchaV3(websiteURL, websiteKey, pageAction); +``` + +Solving reCAPTCHA Mobile +To solve reCAPTCHA Mobile challenges, use the recaptchaMobile method: + +```typescript +const result = await nextCaptcha.recaptchaMobile(websiteURL, websiteKey); +``` + +Solving hCaptcha +To solve hCaptcha challenges, use the hcaptcha method: + +```typescript +const result = await nextCaptcha.hcaptcha(websiteURL, websiteKey); +``` + +Solving hCaptcha Enterprise +To solve hCaptcha Enterprise challenges, use the hcaptchaEnterprise method: + +``` +const result = await nextCaptcha.hcaptchaEnterprise(websiteURL, websiteKey, enterprisePayload); +``` + +Solving FunCaptcha +To solve FunCaptcha challenges, use the funcaptcha method: + +``` +const result = await nextCaptcha.funcaptcha(websitePublicKey); +``` + +Checking Account Balance +To check your NextCaptcha account balance, use the getBalance method: + +``` +const balance = await nextCaptcha.getBalance(); +console.log(`Account balance: ${balance}`); +``` + +## Error Handling + +If an error occurs while solving a captcha, the SDK will throw an error. You can catch and handle these errors using a +try-catch block. + +## Contributing + +If you find any bugs or have suggestions for improvement, please feel free to submit an issue or send a pull request. We +welcome all contributions! + +## License + +This project is licensed under the MIT License. For more information, please see the LICENSE file. diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4adf70a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,431 @@ +{ + "name": "nextcaptcha/captcha-solver", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nextcaptcha/captcha-solver", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "axios": "^1.6.8" + }, + "devDependencies": { + "@types/node": "^20.8.7", + "@types/node-fetch": "^2.5.7", + "dotenv": "^16.0.3", + "jaguarjs-jsdoc": "^1.0.2", + "jsdoc": "^4.0.2", + "typescript": "^4.9.4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", + "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/jaguarjs-jsdoc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jaguarjs-jsdoc/-/jaguarjs-jsdoc-1.1.0.tgz", + "integrity": "sha512-Ku9mk3NrRcvzg8HLgHroatMevfwiSriGQM3r+ATv+ZG2VBqbhnXE6hqMqYEYCXI4D6kM/YF7shWhxc27Pd57Rw==", + "dev": true, + "dependencies": { + "taffydb": "^2.7.2", + "underscore": "^1.7.0" + } + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", + "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/taffydb": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.3.tgz", + "integrity": "sha512-GQ3gtYFSOAxSMN/apGtDKKkbJf+8izz5YfbGqIsUc7AMiQOapARZ76dhilRY2h39cynYxBFdafQo5HUL5vgkrg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5b18021 --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "nextcaptcha/captcha-solver", + "version": "1.0.0", + "description": "NextCaptcha Captcha Solving Service Api Wrapper for Typescript to solving recaptcha v2, v3,recapthcha moible,hcaptcha,funcaptcha", + "main": "dist/index.js", + "repository": "https://github.com/nextcaptcha/nextcaptcha-typescript", + "license": "MIT", + "author": "nextcaptcha", + "bugs": { + "url": "https://github.com/nextcaptcha/nextcaptcha-typescript/issues" + }, + "homepage": "https://github.com/nextcaptcha/nextcaptcha-typescript", + "types": "dist/index.d.ts", + "keywords": [ + "nextcaptcha", + "api", + "bypass captcha", + "captcha solving service", + "captchasolver", + "recaptcha solver", + "recaptcha mobile solver", + "hcaptcha solver", + "funcaptcha solver" + ], + "repository": { + "type": "git", + "url": "https://github.com/your-username/nextcaptcha.git" + }, + "scripts": { + "build": "tsc", + "prepublish": "npm run build" + }, + "files": [ + "dist" + ], + "dependencies": { + "axios": "^1.6.8" + }, + "devDependencies": { + "@types/node": "^16.11.45", + "typescript": "^4.7.4" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..dbc3c68 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,299 @@ +import axios, {AxiosInstance} from 'axios'; + +// Define constants representing different types of captcha tasks +const RECAPTCHAV2_TYPE = "RecaptchaV2TaskProxyless"; +const RECAPTCHAV2_ENTERPRISE_TYPE = "RecaptchaV2EnterpriseTaskProxyless"; +const RECAPTCHAV3_PROXYLESS_TYPE = "RecaptchaV3TaskProxyless"; +const RECAPTCHAV3_TYPE = "RecaptchaV3Task"; +const RECAPTCHA_MOBILE_TYPE = "RecaptchaMobileProxyless"; +const HCAPTCHA_TYPE = "HCaptchaTask"; +const HCAPTCHA_PROXYLESS_TYPE = "HCaptchaTaskProxyless"; +const HCAPTCHA_ENTERPRISE_TYPE = "HCaptchaEnterpriseTask"; +const FUNCAPTCHA_TYPE = "FunCaptchaTask"; +const FUNCAPTCHA_PROXYLESS_TYPE = "FunCaptchaTaskProxyless"; + +// Define the timeout (in seconds) for tasks +const TIMEOUT = 45; + +// Define constants representing different task statuses +const PENDING_STATUS = "pending"; +const PROCESSING_STATUS = "processing"; +const READY_STATUS = "ready"; +const FAILED_STATUS = "failed"; + +// Define a custom error class +class TaskBadParametersError extends Error { +} + +// Define the ApiClient class for communicating with the NextCaptcha API +class ApiClient { + private client: AxiosInstance; + + constructor(apiKey: string) { + // Initialize the Axios client with the API base URL and API key + this.client = axios.create({ + baseURL: "https://api.nextcaptcha.com", + headers: { + "Content-Type": "application/json", + "x-api-key": apiKey, + }, + }); + } + + // Send a task to the NextCaptcha API + async send(task: any): Promise { + try { + // Send a POST request to the /createTask endpoint with the task data + const response = await this.client.post("/createTask", task); + return response.data; + } catch (error) { + console.error("Error creating task:", error); + throw error; + } + } + + // Get the result of a task from the NextCaptcha API + async getTaskResult(taskId: string): Promise { + try { + // Send a POST request to the /getTaskResult endpoint with the task ID + const response = await this.client.post("/getTaskResult", {taskId}); + return response.data; + } catch (error) { + console.error("Error getting task result:", error); + throw error; + } + } + + // Get the account balance from the NextCaptcha API + async getBalance(): Promise { + try { + // Send a POST request to the /getBalance endpoint + const response = await this.client.post("/getBalance"); + return response.data.balance; + } catch (error) { + console.error("Error getting balance:", error); + throw error; + } + } +} + +// Define the NextCaptcha class for interacting with the NextCaptcha service +class NextCaptcha { + private api: ApiClient; + + constructor(apiKey: string) { + // Initialize the ApiClient with the provided API key + this.api = new ApiClient(apiKey); + } + + // Wait for a task to complete and return the result + async waitForResult(taskId: string): Promise { + console.log(`Waiting for task ${taskId} to complete...`); + const startTime = Date.now(); + + while (true) { + // Get the task result from the API + const result = await this.api.getTaskResult(taskId); + + // Check the task status + if (result.status === READY_STATUS) { + // Task is completed successfully + console.info(`Task ${taskId} completed in ${(Date.now() - startTime) / 1000} seconds`); + return result; + } else if (result.status === FAILED_STATUS) { + // Task failed + console.error(`Task ${taskId} failed`); + throw new Error("Task failed"); + } else if (Date.now() - startTime >= TIMEOUT * 1000) { + // Task timed out + console.error(`Task ${taskId} timed out`); + throw new Error("Task timed out"); + } else { + // Task is still pending or processing, wait for a short interval before checking again + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + } + } + + // Solve a reCAPTCHA v2 task + async recaptchaV2( + websiteURL: string, + websiteKey: string, + minScore: number = 0.3, + proxyType: string = "", + proxyAddress: string = "", + proxyPort: number = 0, + proxyLogin: string = "", + proxyPassword: string = "" + ): Promise { + const task: any = { + type: RECAPTCHAV2_TYPE, + websiteURL: websiteURL, + websiteKey: websiteKey, + minScore: minScore, + }; + + if (proxyAddress) { + task.type = RECAPTCHAV2_ENTERPRISE_TYPE; + task.proxyType = proxyType; + task.proxyAddress = proxyAddress; + task.proxyPort = proxyPort; + task.proxyLogin = proxyLogin; + task.proxyPassword = proxyPassword; + } + + // Send the task to the API and wait for the result + const taskId = await this.api.send(task); + return this.waitForResult(taskId); + } + + // Solve a reCAPTCHA v3 task + async recaptchaV3( + websiteURL: string, + websiteKey: string, + pageAction: string, + minScore: number = 0.3, + proxyType: string = "", + proxyAddress: string = "", + proxyPort: number = 0, + proxyLogin: string = "", + proxyPassword: string = "" + ): Promise { + const task: any = { + type: RECAPTCHAV3_PROXYLESS_TYPE, + websiteURL: websiteURL, + websiteKey: websiteKey, + pageAction: pageAction, + minScore: minScore, + }; + + if (proxyAddress) { + task.type = RECAPTCHAV3_TYPE; + task.proxyType = proxyType; + task.proxyAddress = proxyAddress; + task.proxyPort = proxyPort; + task.proxyLogin = proxyLogin; + task.proxyPassword = proxyPassword; + } + + // Send the task to the API and wait for the result + const taskId = await this.api.send(task); + return this.waitForResult(taskId); + } + + // Solve a reCAPTCHA mobile task + async recaptchaMobile( + websiteURL: string, + websiteKey: string, + invisibleMode: boolean = false + ): Promise { + const task = { + type: RECAPTCHA_MOBILE_TYPE, + websiteURL: websiteURL, + websiteKey: websiteKey, + isInvisible: invisibleMode, + }; + + // Send the task to the API and wait for the result + const taskId = await this.api.send(task); + return this.waitForResult(taskId); + } + + // Solve an hCaptcha task + async hcaptcha( + websiteURL: string, + websiteKey: string, + enterprisePayload: any = {}, + isInvisible: boolean = false, + proxyType: string = "", + proxyAddress: string = "", + proxyPort: number = 0, + proxyLogin: string = "", + proxyPassword: string = "" + ): Promise { + const task: any = { + type: HCAPTCHA_PROXYLESS_TYPE, + websiteURL: websiteURL, + websiteKey: websiteKey, + isInvisible: isInvisible, + enterprisePayload: enterprisePayload, + }; + if (proxyAddress) { + task.type = HCAPTCHA_TYPE; + task.proxyType = proxyType; + task.proxyAddress = proxyAddress; + task.proxyPort = proxyPort; + task.proxyLogin = proxyLogin; + task.proxyPassword = proxyPassword; + } + +// Send the task to the API and wait for the result + const taskId = await this.api.send(task); + return this.waitForResult(taskId); + } + + // Solve an hCaptcha Enterprise task + async hcaptchaEnterprise( + websiteURL: string, + websiteKey: string, + enterprisePayload: any = {}, + isInvisible: boolean = false, + proxyType: string = "", + proxyAddress: string = "", + proxyPort: number = 0, + proxyLogin: string = "", + proxyPassword: string = "" + ): Promise { + const task = { + type: HCAPTCHA_ENTERPRISE_TYPE, + websiteURL: websiteURL, + websiteKey: websiteKey, + enterprisePayload: enterprisePayload, + isInvisible: isInvisible, + proxyType: proxyType, + proxyAddress: proxyAddress, + proxyPort: proxyPort, + proxyLogin: proxyLogin, + proxyPassword: proxyPassword, + }; + // Send the task to the API and wait for the result + const taskId = await this.api.send(task); + return this.waitForResult(taskId); + } + + // Solve a FunCaptcha task + async funcaptcha( + websitePublicKey: string, + websiteURL: string = "", + data: string = "", + proxyType: string = "", + proxyAddress: string = "", + proxyPort: number = 0, + proxyLogin: string = "", + proxyPassword: string = "" + ): Promise { + const task: any = { + type: FUNCAPTCHA_PROXYLESS_TYPE, + websiteURL: websiteURL, + websitePublicKey: websitePublicKey, + data: data, + }; + if (proxyAddress) { + task.type = FUNCAPTCHA_TYPE; + task.proxyType = proxyType; + task.proxyAddress = proxyAddress; + task.proxyPort = proxyPort; + task.proxyLogin = proxyLogin; + task.proxyPassword = proxyPassword; + } + +// Send the task to the API and wait for the result + const taskId = await this.api.send(task); + return this.waitForResult(taskId); + } + + // Get the account balance + async getBalance(): Promise { + return this.api.getBalance(); + } +}