├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── ci.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── logo └── logo.png ├── ninjemail ├── __init__.py ├── captcha_solvers │ ├── NopeCHA-CAPTCHA-Solver │ │ ├── background.js │ │ ├── captcha │ │ │ ├── awscaptcha.js │ │ │ ├── funcaptcha.js │ │ │ ├── hcaptcha.js │ │ │ ├── perimeterx.js │ │ │ ├── recaptcha.js │ │ │ ├── textcaptcha.js │ │ │ └── turnstile.js │ │ ├── eventhook.js │ │ ├── eventhook │ │ │ └── loader.js │ │ ├── icon │ │ │ ├── 128.png │ │ │ ├── 128g.png │ │ │ ├── 16.png │ │ │ ├── 16g.png │ │ │ ├── 32.png │ │ │ ├── 32g.png │ │ │ ├── 48.png │ │ │ └── 48g.png │ │ ├── locate.js │ │ ├── manifest.json │ │ ├── pages │ │ │ ├── funcaptcha-demo.js │ │ │ ├── integrate.js │ │ │ └── setup.js │ │ ├── popup.css │ │ ├── popup.html │ │ ├── popup.js │ │ └── setup.html │ ├── __init__.py │ ├── capsolver-chrome-extension │ │ ├── Packaged.capsolver-automatic.zip │ │ ├── _locales │ │ │ ├── en │ │ │ │ └── messages.json │ │ │ ├── es │ │ │ │ └── messages.json │ │ │ ├── ru │ │ │ │ └── messages.json │ │ │ └── zh │ │ │ │ └── messages.json │ │ ├── assets │ │ │ ├── config.js │ │ │ ├── content.css │ │ │ ├── images │ │ │ │ ├── logo.png │ │ │ │ └── logo_solved.png │ │ │ └── inject │ │ │ │ ├── inject-aws.js │ │ │ │ ├── inject-funcaptcha.js │ │ │ │ ├── inject-hcaptcha.js │ │ │ │ ├── inject-recaptcha.js │ │ │ │ ├── injected.js │ │ │ │ └── solvedCallback.js │ │ ├── aws-recognition.js │ │ ├── background.js │ │ ├── core-content-script.js │ │ ├── dom.js │ │ ├── funcaptcha-recognition.js │ │ ├── hcaptcha-recognition.js │ │ ├── icons │ │ │ ├── icon-128x128.png │ │ │ ├── icon-16x16.png │ │ │ └── icon-48x48.png │ │ ├── image-to-text.js │ │ ├── manifest.json │ │ ├── my-content-script.js │ │ ├── recaptcha-recognition.js │ │ └── www │ │ │ ├── assets │ │ │ ├── ErrorNotFound.d890cd68.js │ │ │ ├── KFOkCnqEu92Fr1MmgVxIIzQ.34e9582c.woff │ │ │ ├── KFOlCnqEu92Fr1MmEU9fBBc-.9ce7f3ac.woff │ │ │ ├── KFOlCnqEu92Fr1MmSU5fBBc-.bf14c7d7.woff │ │ │ ├── KFOlCnqEu92Fr1MmWUlfBBc-.e0fd57c0.woff │ │ │ ├── KFOlCnqEu92Fr1MmYUtfBBc-.f6537e32.woff │ │ │ ├── KFOmCnqEu92Fr1Mu4mxM.f2abf7fb.woff │ │ │ ├── Poppins-Black.9f39397b.woff2 │ │ │ ├── Poppins-BlackItalic.fc73cdef.woff2 │ │ │ ├── Poppins-Bold.d83ab9cc.woff2 │ │ │ ├── Poppins-BoldItalic.f401d78d.woff2 │ │ │ ├── Poppins-ExtraBold.b98326c2.woff2 │ │ │ ├── Poppins-ExtraBoldItalic.4ed4ee3c.woff2 │ │ │ ├── Poppins-ExtraLight.f5b6d5dd.woff2 │ │ │ ├── Poppins-ExtraLightItalic.70eb32b6.woff2 │ │ │ ├── Poppins-Italic.e4f71a95.woff2 │ │ │ ├── Poppins-Light.fb1ca566.woff2 │ │ │ ├── Poppins-LightItalic.bda4ebaf.woff2 │ │ │ ├── Poppins-Medium.9b9b4a38.woff2 │ │ │ ├── Poppins-MediumItalic.7d831f05.woff2 │ │ │ ├── Poppins-Regular.efb99a75.woff2 │ │ │ ├── Poppins-SemiBold.f5bbc891.woff2 │ │ │ ├── Poppins-SemiBoldItalic.631bd3f6.woff2 │ │ │ ├── Poppins-Thin.7c230e71.woff2 │ │ │ ├── Poppins-ThinItalic.a1a633c9.woff2 │ │ │ ├── Union.e4f5e32d.svg │ │ │ ├── arrow.1ab57550.svg │ │ │ ├── aws.08ef8f27.svg │ │ │ ├── balance.ec909fe5.svg │ │ │ ├── cloudflare.a164bb78.svg │ │ │ ├── copy.b3d46815.svg │ │ │ ├── dataDome.047813e4.svg │ │ │ ├── en-US.553867d3.svg │ │ │ ├── es.6fe80291.svg │ │ │ ├── flUhRq6tzZclQEJ-Vdg-IuiaDsNa.fd84f88b.woff │ │ │ ├── flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.83be7b2f.woff2 │ │ │ ├── funCaptcha.4f6d4ba4.svg │ │ │ ├── geetest.5dfc422c.svg │ │ │ ├── hCaptcha.0406a4eb.svg │ │ │ ├── index.2a9cb723.js │ │ │ ├── index.ef470009.css │ │ │ ├── key.201fc3f4.svg │ │ │ ├── lock.8b188c3a.svg │ │ │ ├── logo-text.10d5eeb5.png │ │ │ ├── logo-text.e47c19eb.svg │ │ │ ├── logo.eb4b912e.png │ │ │ ├── question.6085c9ed.svg │ │ │ ├── reCaptcha.63436d93.svg │ │ │ ├── ru.6c62f886.svg │ │ │ ├── settings.8bf367a7.svg │ │ │ ├── success.42815aad.svg │ │ │ ├── textToImage.8dbe0bf9.svg │ │ │ ├── tips.e99d9ebe.svg │ │ │ └── zh-CN.c1f22841.svg │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ └── logo.png │ ├── capsolver_captcha_solver-1.10.4.crx │ ├── capsolver_captcha_solver-1.10.4.xpi │ └── noptcha-0.4.9.xpi ├── config.toml ├── config │ └── __init__.py ├── email_providers │ ├── __init__.py │ ├── gmail.py │ ├── outlook.py │ └── yahoo.py ├── ninjemail_manager.py ├── sms_services │ ├── __init__.py │ ├── fivesim.py │ ├── getsmscode.py │ └── smspool.py ├── tests │ ├── __init__.py │ ├── test_email_gmail.py │ ├── test_email_outlook.py │ ├── test_email_yahoo.py │ ├── test_manager.py │ ├── test_sms_5sim.py │ ├── test_sms_getsmscode.py │ ├── test_sms_smspool.py │ ├── test_utils.py │ └── test_webdriver_utils.py └── utils │ ├── __init__.py │ ├── proxy_auth_ext │ ├── background.js │ └── manifest.json │ ├── web_helpers.py │ └── webdriver_utils.py └── requirements.txt /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: ['https://david96182.github.io/support-my-work/'] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Specific configuration 16 | 2. Services used 17 | 4. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Desktop (please complete the following information):** 26 | - OS: [e.g. iOS] 27 | - Browser [e.g. chrome, safari] 28 | - Version [e.g. 22] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Test and Code Coverage 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Set up Python 3.11 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: "3.11" 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 27 | - name: Test with pytest 28 | run: | 29 | pytest --cov 30 | - name: Upload coverage to Codecov 31 | uses: codecov/codecov-action@v4 32 | with: 33 | flags: smart-tests 34 | verbose: true 35 | env: 36 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | # logging 163 | logs/ 164 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Ninjemail 2 | 3 | Thank you for considering contributing to Ninjemail! This document provides guidelines on how to contribute to this project. 4 | 5 | ### Setting Up Your Development Environment 6 | 7 | 1. **Fork the Repository**: Go to the [project repository](https://github.com/david96182/ninjemail) and click on the "Fork" button at the top right corner. This will create a copy of the repository in your GitHub account. 8 | 2. **Clone Your Fork**: Clone your forked repository to your local machine. Replace `yourusername` with your GitHub username and `yourproject` with the name of your project. 9 | 3. **Project installation**: Follow the project [installation steps](https://github.com/david96182/ninjemail?tab=readme-ov-file#installation). 10 | 11 | ## Issue Reporting 12 | 13 | If you find a bug or have a feature request, please open an issue on the [issue tracker](https://github.com/david96182/ninjemail/issues). When filing an issue, make sure to: 14 | 15 | - Provide a clear and descriptive title. 16 | - Describe the issue in as much detail as possible. 17 | - Include steps to reproduce the issue. 18 | - Mention the configuration of the project you're using. 19 | 20 | ## Pull Requests 21 | 22 | If you've made changes that you'd like to contribute back to the project, you can open a pull request. Here's how: 23 | 1. **Fork the Repository**: If you haven't already, fork the repository. 24 | 2. **Create a New Branch**: Create a new branch for your changes. It's a good practice to name your branch according to the issue you're addressing. 25 | 3. **Commit Your Changes**: Commit your changes with a clear and descriptive commit message. 26 | 4. **Push Your Changes**: Push your changes to your forked repository. 27 | 5. **Open a Pull Request**: Go to your forked repository on GitHub and click on the "New pull request" button. 28 | 29 | ## Code Style 30 | 31 | When contributing code, please follow the project's code style. This might include: 32 | 33 | - Indentation and spacing 34 | - Naming conventions 35 | - Comment style 36 | 37 | ## Testing 38 | 39 | If your contribution includes code changes, please include tests that cover your changes. This helps ensure that your changes work as expected and don't introduce new issues. 40 | 41 | ## Documentation 42 | 43 | If your contribution includes new features or changes to existing features, please update the documentation accordingly. This includes the README files and any other relevant documentation. 44 | 45 | ## License 46 | 47 | By contributing to Ninjemail, you agree that your contributions will be licensed under its [LICENSE](LICENSE). 48 | 49 | --- 50 | 51 | Thank you for contributing to [Your Project Name]! We look forward to your contributions. 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 David Puerta Martín 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /logo/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/logo/logo.png -------------------------------------------------------------------------------- /ninjemail/__init__.py: -------------------------------------------------------------------------------- 1 | from .ninjemail_manager import Ninjemail 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/captcha/awscaptcha.js: -------------------------------------------------------------------------------- 1 | (()=>{var s=chrome;var h="https://api.nopecha.com",n="https://www.nopecha.com",S="https://developers.nopecha.com",V={doc:{url:S,automation:{url:`${S}/guides/extension_advanced/#automation-build`}},api:{url:h,recognition:{url:`${h}/recognition`},status:{url:`${h}/status`}},www:{url:n,annoucement:{url:`${n}/json/announcement.json`},demo:{url:`${n}/demo`,hcaptcha:{url:`${n}/demo/hcaptcha`},recaptcha:{url:`${n}/demo/recaptcha`},funcaptcha:{url:`${n}/demo/funcaptcha`},awscaptcha:{url:`${n}/demo/awscaptcha`},turnstile:{url:`${n}/demo/turnstile`},textcaptcha:{url:`${n}/demo/textcaptcha`},perimeterx:{url:`${n}/demo/perimeterx`}},manage:{url:`${n}/manage`},pricing:{url:`${n}/pricing`},setup:{url:`${n}/setup`}},discord:{url:`${n}/discord`},github:{url:`${n}/github`,release:{url:`${n}/github/release`}}};function v(e){let t=("6146a541f7b2046020e84d44aa2e1e120f2ad8b75ac9b6fc236f65f737a7006f"+e).split("").map(o=>o.charCodeAt(0));return x(t)}var M=new Uint32Array(256);for(let e=256;e--;){let t=e;for(let o=8;o--;)t=t&1?3988292384^t>>>1:t>>>1;M[e]=t}function x(e){let t=-1;for(let o of e)t=t>>>8^M[t&255^o];return(t^-1)>>>0}async function a(e,t){let o=""+[+new Date,performance.now(),Math.random()],[u,c]=await new Promise(f=>{s.runtime.sendMessage([o,e,...t],f)});if(u===v(o))return c}function B(){let e;return t=>e||(e=t().finally(()=>e=void 0),e)}var Q=B(),i;function C(){return Q(async()=>(i||(i=await a("settings::get",[])),i))}function q(e){i&&(i={...i,...e},A(i))}function m(){return i}function r(e){return new Promise(t=>setTimeout(t,e))}var H=[];function b(e,t){e.timedout=!1,H.push(e);let o,u=setInterval(async()=>{await $(e,m())||(clearTimeout(o),clearInterval(u))},400);t&&(o=setTimeout(()=>clearInterval(u),t),e.timedout=!0)}async function $(e,t){if(e.timedout)return!1;let o=e.condition(t);if(o===e.running())return!1;if(!o&&e.running())return e.quit(),!1;if(o&&!e.running()){for(;!e.ready();)await r(200);return e.start(),!1}}function A(e){H.forEach(t=>$(t,e))}function k(){s.runtime.connect({name:"stream"}).onMessage.addListener(t=>{t.event==="settingsUpdate"&&q(t.settings)})}function w(e){if(document.readyState!=="loading")setTimeout(e,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),e()},addEventListener("DOMContentLoaded",t)}}var j,_=!1;function L(){return!!(document.querySelector("#captcha-container")&&document.querySelector("#amzn-captcha-verify-button"))}function R(){_=!0,F()}function T(){j.disconnect(),_=!1}function E(){return _}async function F(){await r(400),document.querySelector("#amzn-captcha-verify-button")?.click()}function P(){return!!(document.querySelector("#captcha-container")||document.querySelector("#amzn-captcha-verify-button"))}async function N(e,t){let o={v:s.runtime.getManifest().version,key:K(e)};return o.url=await a("tab::getURL",[]),o}function K(e){return!e.keys||!e.keys.length?e.key:e.keys[Math.floor(Math.random()*e.keys.length)]}var d,y=!1;function z(){if(O(document))return!0;for(let e of document.querySelectorAll("awswaf-captcha")){let t=e.shadowRoot;if(O(t))return!0}return!1}function I(){y=!0;let e=t=>{t.filter(o=>o.type==="childList"&&o.addedNodes.length).map(o=>[...o.addedNodes]).flat().filter(o=>o.nodeName==="AWSWAF-CAPTCHA").map(o=>o.shadowRoot).forEach(o=>{d.observe(o,{subtree:!0,childList:!0}),l(o)}),[3,4,5].includes(t.length)?l(t[0].target.parentElement):t.length===1&&t[0].addedNodes.length&&t[0].addedNodes[0].id==="root"&&l(t[0].addedNodes[0])};d=new MutationObserver(e),d.observe(document,{subtree:!0,childList:!0}),l(document),document.querySelectorAll("awswaf-captcha").forEach(t=>{let o=t.shadowRoot;d.observe(o,{subtree:!0,childList:!0}),l(o)})}function U(){d.disconnect(),y=!1}function W(){return y}function l(e){let t=e.querySelector("#amzn-btn-audio-internal, #amzn-btn-audio");e.querySelector("audio")||t?.click(),e.querySelector("audio")&&G(e),(e.querySelector("audio")||t)&&a("tab::registerDetectedCaptcha",["awscaptcha"])}function O(e){let t=e.querySelector("#amzn-btn-audio-internal, #amzn-btn-audio");return!!(e.querySelector("audio")||t)}var D;async function G(e){let t=e.querySelector("audio").src.replace("data:audio/aac;base64,","");if(t===D||(D=t,!t))return;let o=m(),u=new Date().valueOf(),c=await a("api::recognition",[{type:"awscaptcha",audio_data:[t],...await N(o)}]);if(!c||"error"in c)return;let f=new Date().valueOf();if(o.awscaptcha_solve_delay){let p=o.awscaptcha_solve_delay_time-f+u;p>0&&await r(p)}let g=c.data[0];g?(e.querySelector("input").value=g,await r(200),e.querySelector("#amzn-btn-verify-internal").click()):e.querySelector("#amzn-btn-refresh-internal").click()}async function J(){let e=!1;for(let o=0;o<3;o++)if(await r(1e3),P()){e=!0;break}if(!e)return;k(),await C(),await a("tab::registerDetectedCaptcha",["awscaptcha"]);let t=location.hostname;b({name:"awscaptcha/auto-open",condition:o=>o.enabled&&o.awscaptcha_auto_open&&!o.disabled_hosts.includes(t),ready:L,start:R,quit:T,running:E}),b({name:"awscaptcha/auto-solve",condition:o=>o.enabled&&o.awscaptcha_auto_solve&&!o.disabled_hosts.includes(t),ready:z,start:I,quit:U,running:W})}w(J);})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/captcha/funcaptcha.js: -------------------------------------------------------------------------------- 1 | (()=>{function D(){if("ancestorOrigins"in location){let t=location.ancestorOrigins,n=t[1]??t[0];if(n)return n.split("/")[2]}let e=document.referrer;return e?e.split("/")[2]:location.origin}var h=chrome;var x="https://api.nopecha.com",i="https://www.nopecha.com",L="https://developers.nopecha.com",_e={doc:{url:L,automation:{url:`${L}/guides/extension_advanced/#automation-build`}},api:{url:x,recognition:{url:`${x}/recognition`},status:{url:`${x}/status`}},www:{url:i,annoucement:{url:`${i}/json/announcement.json`},demo:{url:`${i}/demo`,hcaptcha:{url:`${i}/demo/hcaptcha`},recaptcha:{url:`${i}/demo/recaptcha`},funcaptcha:{url:`${i}/demo/funcaptcha`},awscaptcha:{url:`${i}/demo/awscaptcha`},turnstile:{url:`${i}/demo/turnstile`},textcaptcha:{url:`${i}/demo/textcaptcha`},perimeterx:{url:`${i}/demo/perimeterx`}},manage:{url:`${i}/manage`},pricing:{url:`${i}/pricing`},setup:{url:`${i}/setup`}},discord:{url:`${i}/discord`},github:{url:`${i}/github`,release:{url:`${i}/github/release`}}};function E(e){let t=("6146a541f7b2046020e84d44aa2e1e120f2ad8b75ac9b6fc236f65f737a7006f"+e).split("").map(n=>n.charCodeAt(0));return q(t)}var P=new Uint32Array(256);for(let e=256;e--;){let t=e;for(let n=8;n--;)t=t&1?3988292384^t>>>1:t>>>1;P[e]=t}function q(e){let t=-1;for(let n of e)t=t>>>8^P[t&255^n];return(t^-1)>>>0}async function u(e,t){let n=""+[+new Date,performance.now(),Math.random()],[a,o]=await new Promise(r=>{h.runtime.sendMessage([n,e,...t],r)});if(a===E(n))return o}function b(){let e;return t=>e||(e=t().finally(()=>e=void 0),e)}var oe=b(),m;function O(){return oe(async()=>(m||(m=await u("settings::get",[])),m))}function F(e){m&&(m={...m,...e},N(m))}function _(){return m}function l(e){return new Promise(t=>setTimeout(t,e))}var z=[];function T(e,t){e.timedout=!1,z.push(e);let n,a=setInterval(async()=>{await U(e,_())||(clearTimeout(n),clearInterval(a))},400);t&&(n=setTimeout(()=>clearInterval(a),t),e.timedout=!0)}async function U(e,t){if(e.timedout)return!1;let n=e.condition(t);if(n===e.running())return!1;if(!n&&e.running())return e.quit(),!1;if(n&&!e.running()){for(;!e.ready();)await l(200);return e.start(),!1}}function N(e){z.forEach(t=>U(t,e))}function W(){h.runtime.connect({name:"stream"}).onMessage.addListener(t=>{t.event==="settingsUpdate"&&F(t.settings)})}function S(e){if(document.readyState!=="loading")setTimeout(e,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),e()},addEventListener("DOMContentLoaded",t)}}var Oe=b();var re=["#home_children_button","#wrong_children_button","#wrongTimeout_children_button","button[data-theme*=verifyButton]","[class*=game-fail] .button",".error .button"],G=["#root","#app","#home","#wrong","#wrongTimeout",".container[dir]"].join(", "),k,C=!1;function V(){return!!document.querySelector(G)}function j(){C=!0;let e=()=>{ie(),document.querySelectorAll(G).forEach(t=>{k.observe(t,{childList:!0})})};k=new MutationObserver(e),e()}function Q(){k.disconnect(),C=!1}function K(){return C}async function ie(){await l(400),re.map(e=>document.querySelector(e)).filter(e=>e).map(e=>e.click())}function ce(e,t){let n=document.createElement("canvas");return n.width=e,n.height=t,n}function M(e){return e.toDataURL("image/jpeg").replace(/data:image\/[a-z]+;base64,/g,"")}function se(e){try{e.getContext("2d").getImageData(0,0,1,1)}catch{return!0}return!1}async function I(e,t,n=1e4){if(!t&&!e.complete&&!await new Promise(c=>{let d=setTimeout(()=>{c(!1)},n);e.addEventListener("load",()=>{clearTimeout(d),c(!0)})}))return;let a=ce(e.naturalWidth||t?.clientWidth,e.naturalHeight||t?.clientHeight);return a.getContext("2d").drawImage(e,0,0),!se(a)&&a}async function B(e){let n=getComputedStyle(e).backgroundImage;if(!n||n==="none")if("src"in e&&e.src)n=`url("${e.src}")`;else return;if("computedStyleMap"in e){let s=e.computedStyleMap().get("background-image");if(s instanceof CSSImageValue){let f=await I(s,e);if(f)return f}}let a=/"(.+)"/.exec(n);if(!a)return;n=a[1];let o=document.createElement("a");if(o.href=n,new URL(o.href).origin===document.location.origin){let s=new Image;s.crossOrigin="anonymous",s.src=n;let f=await I(s);if(f)return f}let r=await u("fetch::asData",[n,{}]),c=new Image;c.crossOrigin="anonymous",c.src=r.data;let d=await I(c);if(d)return d}function ue(e,t,n,a){let o=(a*t+n)*4;return[e[o],e[o+1],e[o+2]]}function le(e,t){return e.every(n=>n<=t)}function de(e,t){return e.every(n=>n>=t)}function $(e,t=0,n=230,a=.99){let o=e.getContext("2d"),r=o.canvas.width,c=o.canvas.height;if(r===0||c===0)return!0;let d=o.getImageData(0,0,r,c).data,s=0;for(let w=0;wa}function J(){return[]}function X(e){return new Promise(t=>{e.push(t)})}function g(e){e.forEach(t=>t()),e.splice(0)}async function Y(e,t){let n={v:h.runtime.getManifest().version,key:me(e)};return n.url=await u("tab::getURL",[]),n}function me(e){return!e.keys||!e.keys.length?e.key:e.keys[Math.floor(Math.random()*e.keys.length)]}var p=J(),H,y=!1;function ee(){return R()!==void 0}function te(){y=!0,g(p),H=new MutationObserver(e=>{let t=R();for(let n of e)if(n.type==="childList"&&n.removedNodes.length&&["app","game"].includes(n.target.id)){setTimeout(()=>g(p),200);return}t===1&&e.length===24&&!document.querySelector(".loading-spinner")&&setTimeout(()=>g(p),200),t===2&&[8,13].includes(e.length)&&!document.querySelector(".loading-spinner")&&setTimeout(()=>g(p),200)}),H.observe(document,{childList:!0,subtree:!0,attributes:!0}),fe()}function ne(){H.disconnect(),y=!1,g(p)}function ae(){return y}var ge={[0]:{async getTask(){let e=document.querySelector("#game_children_text h2"),t=document.querySelector("#game_challengeItem_image"),n=[...document.querySelectorAll("#game_children_challenge a")];if(!(!e||!t||n.length!==6))return{payload:{type:"funcaptcha",task:e.textContent,image_data:[t.src.replace(/data:image\/[a-z]+;base64,/g,"")]},cells:n}},async solution(e,t){e.cells.forEach((n,a)=>{t.data[a]&&n.click()})}},[1]:{async getTask(){let e=document.querySelector(".tile-game h2"),t=[...document.querySelectorAll(".challenge-container button")];if(!e||t.length!==6)return;let n=await B(t[0]);if(n&&!$(n))return{payload:{type:"funcaptcha",task:e.textContent,image_data:[M(n)]},cells:t}},async solution(e,t){e.cells.forEach((n,a)=>{t.data[a]&&n.click()})}},[2]:{async getTask(){let e=document.querySelector(".match-game h2"),t=document.querySelector(".key-frame-image");if(!e||!t)return;let n=await B(t);if(n&&!$(n))return{payload:{type:"funcaptcha_match",task:e.textContent,image_data:[M(n)]}}},async solution(e,t){let n=document.querySelector(".right-arrow"),a=t.data.indexOf(!0);for(let r=0;rdocument.querySelector(e)).map(([e,t])=>t)[0]}var Z=!1;async function fe(){if(!Z)for(Z=!0;y;){let e=R();if(e===void 0){await l(500);continue}let t=ge[e],n=await t.getTask();if(!n){await l(500);continue}let a=_(),o=new Date().valueOf(),r=await u("api::recognition",[{...n.payload,...await Y(a,!0)}]);if(!r||"error"in r){await l(2e3);continue}let c=new Date().valueOf();if(a.funcaptcha_solve_delay){let s=a.funcaptcha_solve_delay_time-c+o;s>0&&await l(s)}await t.solution(n,r);let d=setTimeout(()=>{g(p)},1e3*5);await X(p),clearTimeout(d)}}async function he(){W(),await O(),await u("tab::registerDetectedCaptcha",["funcaptcha"]);let e=D();T({name:"funcaptcha/auto-open",condition:t=>t.enabled&&t.funcaptcha_auto_open&&!t.disabled_hosts.includes(e),ready:V,start:j,quit:Q,running:K}),T({name:"funcaptcha/auto-solve",condition:t=>t.enabled&&t.funcaptcha_auto_solve&&!t.disabled_hosts.includes(e),ready:ee,start:te,quit:ne,running:ae})}S(he);})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/captcha/perimeterx.js: -------------------------------------------------------------------------------- 1 | (()=>{var u=chrome;var l="https://api.nopecha.com",n="https://www.nopecha.com",b="https://developers.nopecha.com",L={doc:{url:b,automation:{url:`${b}/guides/extension_advanced/#automation-build`}},api:{url:l,recognition:{url:`${l}/recognition`},status:{url:`${l}/status`}},www:{url:n,annoucement:{url:`${n}/json/announcement.json`},demo:{url:`${n}/demo`,hcaptcha:{url:`${n}/demo/hcaptcha`},recaptcha:{url:`${n}/demo/recaptcha`},funcaptcha:{url:`${n}/demo/funcaptcha`},awscaptcha:{url:`${n}/demo/awscaptcha`},turnstile:{url:`${n}/demo/turnstile`},textcaptcha:{url:`${n}/demo/textcaptcha`},perimeterx:{url:`${n}/demo/perimeterx`}},manage:{url:`${n}/manage`},pricing:{url:`${n}/pricing`},setup:{url:`${n}/setup`}},discord:{url:`${n}/discord`},github:{url:`${n}/github`,release:{url:`${n}/github/release`}}};function _(e){let t=("6146a541f7b2046020e84d44aa2e1e120f2ad8b75ac9b6fc236f65f737a7006f"+e).split("").map(o=>o.charCodeAt(0));return v(t)}var h=new Uint32Array(256);for(let e=256;e--;){let t=e;for(let o=8;o--;)t=t&1?3988292384^t>>>1:t>>>1;h[e]=t}function v(e){let t=-1;for(let o of e)t=t>>>8^h[t&255^o];return(t^-1)>>>0}async function s(e,t){let o=""+[+new Date,performance.now(),Math.random()],[a,f]=await new Promise(T=>{u.runtime.sendMessage([o,e,...t],T)});if(a===_(o))return f}function w(){let e;return t=>e||(e=t().finally(()=>e=void 0),e)}var k=w(),r;function S(){return k(async()=>(r||(r=await s("settings::get",[])),r))}function x(e){r&&(r={...r,...e},y(r))}function c(){return r}function i(e){return new Promise(t=>setTimeout(t,e))}var $=[];function C(e,t){e.timedout=!1,$.push(e);let o,a=setInterval(async()=>{await B(e,c())||(clearTimeout(o),clearInterval(a))},400);t&&(o=setTimeout(()=>clearInterval(a),t),e.timedout=!0)}async function B(e,t){if(e.timedout)return!1;let o=e.condition(t);if(o===e.running())return!1;if(!o&&e.running())return e.quit(),!1;if(o&&!e.running()){for(;!e.ready();)await i(200);return e.start(),!1}}function y(e){$.forEach(t=>B(t,e))}function M(){u.runtime.connect({name:"stream"}).onMessage.addListener(t=>{t.event==="settingsUpdate"&&x(t.settings)})}function d(e){if(document.readyState!=="loading")setTimeout(e,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),e()},addEventListener("DOMContentLoaded",t)}}var p,m=!1;function P(){return!(!g()||!document.querySelector("[role=button]"))}function q(){m=!0,p=new MutationObserver(()=>{document.querySelector("[role=button]").dispatchEvent(new MouseEvent("mouseup"))}),p.observe(document.querySelector('[aria-label="Human challenge"], [aria-label="Press & Hold"]'),{attributes:!0,attributeFilter:["aria-label"]}),N()}function A(){m=!1,p.disconnect()}function H(){return m}function g(){try{return!!(window.top!==window&&window.top.top===window.top&&[...window.top.document.querySelectorAll("script")].some(e=>e.innerText.includes("_pxAppId"))&&document.querySelector('[aria-label="Human challenge"], [aria-label="Press & Hold"]'))}catch{return!1}}async function N(){let e=c();e.perimeterx_solve_delay&&await i(e.perimeterx_solve_delay_time),document.querySelector("[role=button]").dispatchEvent(new MouseEvent("mousedown"))}async function E(){let e=!1;for(let o=0;o<3;o++)if(await i(1e3),g()){e=!0;break}if(!e)return;M(),await S(),await s("tab::registerDetectedCaptcha",["perimeterx"]);let t=location.hostname;C({name:"perimeterx/auto-solve",condition:o=>o.enabled&&o.perimeterx_auto_solve&&!o.disabled_hosts.includes(t),ready:P,start:q,quit:A,running:H})}d(E);})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/captcha/recaptcha.js: -------------------------------------------------------------------------------- 1 | (()=>{function A(){if("ancestorOrigins"in location){let t=location.ancestorOrigins,n=t[1]??t[0];if(n)return n.split("/")[2]}let e=document.referrer;return e?e.split("/")[2]:location.origin}var b=chrome;var B="https://api.nopecha.com",r="https://www.nopecha.com",D="https://developers.nopecha.com",Me={doc:{url:D,automation:{url:`${D}/guides/extension_advanced/#automation-build`}},api:{url:B,recognition:{url:`${B}/recognition`},status:{url:`${B}/status`}},www:{url:r,annoucement:{url:`${r}/json/announcement.json`},demo:{url:`${r}/demo`,hcaptcha:{url:`${r}/demo/hcaptcha`},recaptcha:{url:`${r}/demo/recaptcha`},funcaptcha:{url:`${r}/demo/funcaptcha`},awscaptcha:{url:`${r}/demo/awscaptcha`},turnstile:{url:`${r}/demo/turnstile`},textcaptcha:{url:`${r}/demo/textcaptcha`},perimeterx:{url:`${r}/demo/perimeterx`}},manage:{url:`${r}/manage`},pricing:{url:`${r}/pricing`},setup:{url:`${r}/setup`}},discord:{url:`${r}/discord`},github:{url:`${r}/github`,release:{url:`${r}/github/release`}}};function O(e){let t=("6146a541f7b2046020e84d44aa2e1e120f2ad8b75ac9b6fc236f65f737a7006f"+e).split("").map(n=>n.charCodeAt(0));return N(t)}var q=new Uint32Array(256);for(let e=256;e--;){let t=e;for(let n=8;n--;)t=t&1?3988292384^t>>>1:t>>>1;q[e]=t}function N(e){let t=-1;for(let n of e)t=t>>>8^q[t&255^n];return(t^-1)>>>0}async function d(e,t){let n=""+[+new Date,performance.now(),Math.random()],[o,a]=await new Promise(i=>{b.runtime.sendMessage([n,e,...t],i)});if(o===O(n))return a}function y(){let e;return t=>e||(e=t().finally(()=>e=void 0),e)}var de=y(),p;function V(){return de(async()=>(p||(p=await d("settings::get",[])),p))}function W(e){p&&(p={...p,...e},j(p))}function C(){return p}function l(e){return new Promise(t=>setTimeout(t,e))}var z=[];function E(e,t){e.timedout=!1,z.push(e);let n,o=setInterval(async()=>{await F(e,C())||(clearTimeout(n),clearInterval(o))},400);t&&(n=setTimeout(()=>clearInterval(o),t),e.timedout=!0)}async function F(e,t){if(e.timedout)return!1;let n=e.condition(t);if(n===e.running())return!1;if(!n&&e.running())return e.quit(),!1;if(n&&!e.running()){for(;!e.ready();)await l(200);return e.start(),!1}}function j(e){z.forEach(t=>F(t,e))}function U(){b.runtime.connect({name:"stream"}).onMessage.addListener(t=>{t.event==="settingsUpdate"&&W(t.settings)})}function $(e){if(document.readyState!=="loading")setTimeout(e,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),e()},addEventListener("DOMContentLoaded",t)}}var Xe=y();function J(e){postMessage({source:"nopecha",...e})}function _(e){J(e)}var T,L,H=!1;function Q(){return!!document.querySelector(".recaptcha-checkbox")}function Y(){H=!0,T=new MutationObserver(t=>{t.length===2&&X(),t.length&&t[0].target.classList.contains("recaptcha-checkbox-expired")&&window.location.reload()}),T.observe(document.querySelector(".recaptcha-checkbox"),{attributes:!0});let e=!1;L=new IntersectionObserver(()=>{e||(e=!0,X())},{threshold:0}),L.observe(document.body)}function G(){T.disconnect(),L.disconnect(),H=!1}function K(){return H}async function X(){await l(400),_({action:"click",selector:".recaptcha-checkbox"})}function ge(e,t){let n=document.createElement("canvas");return n.width=e,n.height=t,n}function Z(e){return e.toDataURL("image/jpeg").replace(/data:image\/[a-z]+;base64,/g,"")}function pe(e){try{e.getContext("2d").getImageData(0,0,1,1)}catch{return!0}return!1}async function ee(e,t,n=1e4){if(!t&&!e.complete&&!await new Promise(u=>{let c=setTimeout(()=>{u(!1)},n);e.addEventListener("load",()=>{clearTimeout(c),u(!0)})}))return;let o=ge(e.naturalWidth||t?.clientWidth,e.naturalHeight||t?.clientHeight);return o.getContext("2d").drawImage(e,0,0),!pe(o)&&o}function fe(e,t,n,o){let a=(o*t+n)*4;return[e[a],e[a+1],e[a+2]]}function he(e,t){return e.every(n=>n<=t)}function be(e,t){return e.every(n=>n>=t)}function te(e,t=0,n=230,o=.99){let a=e.getContext("2d"),i=a.canvas.width,u=a.canvas.height;if(i===0||u===0)return!0;let c=a.getImageData(0,0,i,u).data,m=0;for(let v=0;vo}function ne(){return[]}function oe(e){return new Promise(t=>{e.push(t)})}function k(e){e.forEach(t=>t()),e.splice(0)}async function ae(e,t){let n={v:b.runtime.getManifest().version,key:_e(e)};return n.url=await d("tab::getURL",[]),n}function _e(e){return!e.keys||!e.keys.length?e.key:e.keys[Math.floor(Math.random()*e.keys.length)]}var ve,S=ne(),R,w=!1;function ie(){return!!document.querySelector(".rc-imageselect, .rc-imageselect-target")}function ce(){w=!0,k(S);let e;R=new MutationObserver(()=>{clearTimeout(e),e=setTimeout(()=>k(S),200)}),R.observe(document.body,{childList:!0,subtree:!0}),ke()}function se(){R.disconnect(),w=!1,k(S)}function le(){return w}function we(){return document.querySelector(".rc-doscaptcha-header")}function xe(){let e=document.querySelector("#recaptcha-verify-button");return e&&e.getAttribute("disabled")}var ye={[1]:1,[0]:3,[2]:4};async function Ce(){for(;;){await l(1e3);let e=document.querySelector(".rc-imageselect-instructions");if(!e)continue;let t=e.innerText.split(` 2 | `),n=t.slice(0,2).join(" ").replace(/\s+/g," ").trim(),o=[...document.querySelectorAll("table tr td")];if(o.length!==9&&o.length!==16)continue;let a=o.map(c=>c.querySelector("img")).filter(c=>c).filter(c=>c.src.trim());if(a.length!==9&&a.length!==16)continue;let i=o.length===16?2:a.some(c=>c.classList.contains("rc-image-tile-11"))?1:0,u=t.length===3&&i!==2;return{task:n,type:i,cells:o,images:a,waitAfterSolve:u}}}var re=!1;async function ke(){if(!re){for(re=!0;w&&(we()||xe());)await l(1e3);for(;w;){let{task:e,type:t,cells:n,images:o,waitAfterSolve:a}=await Ce(),i=C(),u=new Date().valueOf(),c=[...n];t!==1&&(o=[o[0]]);let m=await Promise.all(o.map(s=>ee(s)));if(t===1){let s=[],x=[];for(let[M,h]of m.entries())h.width!==100||h.height!==100||(s.push(c[M]),x.push(h));c=s,m=x}if(m.length===0){_({action:"click",selector:"#recaptcha-verify-button"}),await l(3e3);continue}let I=!1;for(let s of m)if(te(s)){I=!0;break}if(I){await l(3e3);continue}let v=m.map(Z),f=ye[t],g=await d("api::recognition",[{type:"recaptcha",task:e,image_data:v,grid:[f,f].join("x"),...await ae(i)}]);if(!g||"error"in g){console.warn(`[@nope/recaptcha/${ve}]`,"api error",g),await l(2e3);continue}let ue=new Date().valueOf();if(i.recaptcha_solve_delay){let s=i.recaptcha_solve_delay_time-ue+u;s>0&&await l(s)}let P=t===2?4:3;for(c.forEach((s,x)=>{let M=s.classList.contains("rc-imageselect-tileselected"),h=n.indexOf(s);g.data[x]!==M&&_({action:"click",selector:`tr:nth-child(${Math.floor(h/P)+1}) td:nth-child(${h%P+1})`})}),(!a||!g.data.some(s=>s))&&(await l(200),_({action:"click",selector:"#recaptcha-verify-button"})),await oe(S);document.querySelectorAll(".rc-imageselect-dynamic-selected").length>0;)await l(1e3)}}}async function Se(){U(),await V(),await d("tab::registerDetectedCaptcha",["recaptcha"]);let e=A();location.pathname.endsWith("/anchor")?E({name:"recaptcha/auto-open",condition:t=>t.enabled&&t.recaptcha_auto_open&&!t.disabled_hosts.includes(e),ready:Q,start:Y,quit:G,running:K}):E({name:"recaptcha/auto-solve",condition:t=>t.enabled&&t.recaptcha_auto_solve&&!t.disabled_hosts.includes(e),ready:ie,start:ce,quit:se,running:le})}$(Se);})(); 3 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/captcha/textcaptcha.js: -------------------------------------------------------------------------------- 1 | (()=>{var p=chrome;var y="https://api.nopecha.com",i="https://www.nopecha.com",B="https://developers.nopecha.com",ie={doc:{url:B,automation:{url:`${B}/guides/extension_advanced/#automation-build`}},api:{url:y,recognition:{url:`${y}/recognition`},status:{url:`${y}/status`}},www:{url:i,annoucement:{url:`${i}/json/announcement.json`},demo:{url:`${i}/demo`,hcaptcha:{url:`${i}/demo/hcaptcha`},recaptcha:{url:`${i}/demo/recaptcha`},funcaptcha:{url:`${i}/demo/funcaptcha`},awscaptcha:{url:`${i}/demo/awscaptcha`},turnstile:{url:`${i}/demo/turnstile`},textcaptcha:{url:`${i}/demo/textcaptcha`},perimeterx:{url:`${i}/demo/perimeterx`}},manage:{url:`${i}/manage`},pricing:{url:`${i}/pricing`},setup:{url:`${i}/setup`}},discord:{url:`${i}/discord`},github:{url:`${i}/github`,release:{url:`${i}/github/release`}}};function M(e){let t=("6146a541f7b2046020e84d44aa2e1e120f2ad8b75ac9b6fc236f65f737a7006f"+e).split("").map(n=>n.charCodeAt(0));return I(t)}var T=new Uint32Array(256);for(let e=256;e--;){let t=e;for(let n=8;n--;)t=t&1?3988292384^t>>>1:t>>>1;T[e]=t}function I(e){let t=-1;for(let n of e)t=t>>>8^T[t&255^n];return(t^-1)>>>0}async function g(e,t){let n=""+[+new Date,performance.now(),Math.random()],[a,o]=await new Promise(s=>{p.runtime.sendMessage([n,e,...t],s)});if(a===M(n))return o}function H(){let e;return t=>e||(e=t().finally(()=>e=void 0),e)}var G=H(),m;function $(){return G(async()=>(m||(m=await g("settings::get",[])),m))}function E(e){m&&(m={...m,...e},L(m))}function f(){return m}function r(e){return new Promise(t=>setTimeout(t,e))}var P=[];function D(e,t){e.timedout=!1,P.push(e);let n,a=setInterval(async()=>{await R(e,f())||(clearTimeout(n),clearInterval(a))},400);t&&(n=setTimeout(()=>clearInterval(a),t),e.timedout=!0)}async function R(e,t){if(e.timedout)return!1;let n=e.condition(t);if(n===e.running())return!1;if(!n&&e.running())return e.quit(),!1;if(n&&!e.running()){for(;!e.ready();)await r(200);return e.start(),!1}}function L(e){P.forEach(t=>R(t,e))}function A(){p.runtime.connect({name:"stream"}).onMessage.addListener(t=>{t.event==="settingsUpdate"&&E(t.settings)})}function C(e){if(document.readyState!=="loading")setTimeout(e,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),e()},addEventListener("DOMContentLoaded",t)}}function J(e,t){let n=document.createElement("canvas");return n.width=e,n.height=t,n}function q(e){return e.toDataURL("image/jpeg").replace(/data:image\/[a-z]+;base64,/g,"")}function X(e){try{e.getContext("2d").getImageData(0,0,1,1)}catch{return!0}return!1}async function h(e,t,n=1e4){if(!t&&!e.complete&&!await new Promise(c=>{let u=setTimeout(()=>{c(!1)},n);e.addEventListener("load",()=>{clearTimeout(u),c(!0)})}))return;let a=J(e.naturalWidth||t?.clientWidth,e.naturalHeight||t?.clientHeight);return a.getContext("2d").drawImage(e,0,0),!X(a)&&a}async function N(e){let n=getComputedStyle(e).backgroundImage;if(!n||n==="none")if("src"in e&&e.src)n=`url("${e.src}")`;else return;if("computedStyleMap"in e){let d=e.computedStyleMap().get("background-image");if(d instanceof CSSImageValue){let l=await h(d,e);if(l)return l}}let a=/"(.+)"/.exec(n);if(!a)return;n=a[1];let o=document.createElement("a");if(o.href=n,new URL(o.href).origin===document.location.origin){let d=new Image;d.crossOrigin="anonymous",d.src=n;let l=await h(d);if(l)return l}let s=await g("fetch::asData",[n,{}]),c=new Image;c.crossOrigin="anonymous",c.src=s.data;let u=await h(c);if(u)return u}function Y(e,t,n,a){let o=(a*t+n)*4;return[e[o],e[o+1],e[o+2]]}function Z(e,t){return e.every(n=>n<=t)}function ee(e,t){return e.every(n=>n>=t)}function U(e,t=0,n=230,a=.99){let o=e.getContext("2d"),s=o.canvas.width,c=o.canvas.height;if(s===0||c===0)return!0;let u=o.getImageData(0,0,s,c).data,d=0;for(let x=0;xa}function W(){return[]}function z(e){return new Promise(t=>{e.push(t)})}function b(e){e.forEach(t=>t()),e.splice(0)}async function O(e,t){let n={v:p.runtime.getManifest().version,key:te(e)};return n.url=await g("tab::getURL",[]),n}function te(e){return!e.keys||!e.keys.length?e.key:e.keys[Math.floor(Math.random()*e.keys.length)]}var v=W(),S,_=!1;function j(){let e=f(),t=document.querySelector(e.textcaptcha_image_selector),n=document.querySelector(e.textcaptcha_input_selector);return!t||!n?!1:(g("tab::registerDetectedCaptcha",["textcaptcha"]),!0)}function K(){_=!0,b(v),S=new MutationObserver(async()=>{setTimeout(()=>b(v),200)}),S.observe(document.body,{subtree:!0,childList:!0,attributes:!0}),ae()}function V(){S.disconnect(),_=!1,b(v)}function Q(){return _}async function ne(e){if(e instanceof HTMLCanvasElement)return e;if(e instanceof HTMLImageElement&&(e.src||e.srcset)){let t=await h(e);if(t)return t}return await N(e)}var F=!1;async function ae(){if(F)return;F=!0;let e;for(;_;){let t=f(),n=document.querySelector(t.textcaptcha_image_selector),a=document.querySelector(t.textcaptcha_input_selector);if(!n){await r(500);continue}if(!a){await r(500);continue}if(a.click(),a.focus(),await r(200),a.value!==""){await r(500);continue}let o=await ne(n);if(!o){await r(500);continue}if(U(o)){await r(500);continue}let s=q(o);if(e===s){await r(500);continue}e=s;let c=new Date().valueOf(),u=await g("api::recognition",[{type:"textcaptcha",image_data:[s],...await O(t)}]);if(!u||"error"in u){console.warn("[@nope/textcaptcha] api error",u),await r(2e3);continue}let d=new Date().valueOf();if(t.textcaptcha_solve_delay){let l=t.textcaptcha_solve_delay_time-d+c;l>0&&await r(l)}if(u.data&&u.data.length>0&&!a.value){a.click(),a.focus(),await r(200),a.value=u.data[0];for(let l of u.data[0])a.dispatchEvent(new KeyboardEvent("keydown",{key:l})),await r(50),a.dispatchEvent(new KeyboardEvent("keypress",{key:l})),await r(50),a.dispatchEvent(new KeyboardEvent("keyup",{key:l})),await r(50)}await z(v)}}async function oe(){A(),await $(),await g("tab::registerDetectedCaptcha",["textcaptcha"]);let e=location.hostname;D({name:"textcaptcha/auto-solve",condition:t=>t.enabled&&t.textcaptcha_auto_solve&&!t.disabled_hosts.includes(e)&&!!t.textcaptcha_image_selector&&!!t.textcaptcha_input_selector,ready:j,start:K,quit:V,running:Q})}C(oe);})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/captcha/turnstile.js: -------------------------------------------------------------------------------- 1 | (()=>{var i=chrome;var d="https://api.nopecha.com",n="https://www.nopecha.com",b="https://developers.nopecha.com",R={doc:{url:b,automation:{url:`${b}/guides/extension_advanced/#automation-build`}},api:{url:d,recognition:{url:`${d}/recognition`},status:{url:`${d}/status`}},www:{url:n,annoucement:{url:`${n}/json/announcement.json`},demo:{url:`${n}/demo`,hcaptcha:{url:`${n}/demo/hcaptcha`},recaptcha:{url:`${n}/demo/recaptcha`},funcaptcha:{url:`${n}/demo/funcaptcha`},awscaptcha:{url:`${n}/demo/awscaptcha`},turnstile:{url:`${n}/demo/turnstile`},textcaptcha:{url:`${n}/demo/textcaptcha`},perimeterx:{url:`${n}/demo/perimeterx`}},manage:{url:`${n}/manage`},pricing:{url:`${n}/pricing`},setup:{url:`${n}/setup`}},discord:{url:`${n}/discord`},github:{url:`${n}/github`,release:{url:`${n}/github/release`}}};function h(e){let t=("6146a541f7b2046020e84d44aa2e1e120f2ad8b75ac9b6fc236f65f737a7006f"+e).split("").map(o=>o.charCodeAt(0));return _(t)}var v=new Uint32Array(256);for(let e=256;e--;){let t=e;for(let o=8;o--;)t=t&1?3988292384^t>>>1:t>>>1;v[e]=t}function _(e){let t=-1;for(let o of e)t=t>>>8^v[t&255^o];return(t^-1)>>>0}async function s(e,t){let o=""+[+new Date,performance.now(),Math.random()],[a,g]=await new Promise(N=>{i.runtime.sendMessage([o,e,...t],N)});if(a===h(o))return g}function y(){let e;return t=>e||(e=t().finally(()=>e=void 0),e)}var V=y(),r;function w(){return V(async()=>(r||(r=await s("settings::get",[])),r))}function x(e){r&&(r={...r,...e},S(r))}function c(){return r}function u(e){return new Promise(t=>setTimeout(t,e))}var C=[];function k(e,t){e.timedout=!1,C.push(e);let o,a=setInterval(async()=>{await M(e,c())||(clearTimeout(o),clearInterval(a))},400);t&&(o=setTimeout(()=>clearInterval(a),t),e.timedout=!0)}async function M(e,t){if(e.timedout)return!1;let o=e.condition(t);if(o===e.running())return!1;if(!o&&e.running())return e.quit(),!1;if(o&&!e.running()){for(;!e.ready();)await u(200);return e.start(),!1}}function S(e){C.forEach(t=>M(t,e))}function E(){i.runtime.connect({name:"stream"}).onMessage.addListener(t=>{t.event==="settingsUpdate"&&x(t.settings)})}function l(e){if(document.readyState!=="loading")setTimeout(e,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),e()},addEventListener("DOMContentLoaded",t)}}function $(e){postMessage({source:"nopecha",...e})}function B(e){$(e)}var p,f=!1;function L(){return!!document.querySelector("#challenge-stage")}function P(){f=!0,p=new MutationObserver(e=>{e[0].addedNodes.length>0&&H()}),p.observe(document.querySelector("#challenge-stage"),{childList:!0}),document.querySelector("#challenge-stage .ctp-checkbox-container")&&H()}function T(){p.disconnect(),f=!1}function q(){return f}var m=!1;async function H(){if(m)return;m=!0;let e=c();e.turnstile_solve_delay&&await u(e.turnstile_solve_delay_time),B({action:"click",selector:"input[type=checkbox], #cf-stage area"}),m=!1}async function O(){E(),await w(),await s("tab::registerDetectedCaptcha",["turnstile"]);let e=location.hostname;k({name:"turnstile/auto-solve",condition:t=>t.enabled&&t.turnstile_auto_solve&&!t.disabled_hosts.includes(e),ready:L,start:P,quit:T,running:q})}l(O);})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/eventhook.js: -------------------------------------------------------------------------------- 1 | (()=>{function o(e){postMessage({source:"nopecha",...e})}function l(e){o(e)}})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/eventhook/loader.js: -------------------------------------------------------------------------------- 1 | (()=>{function g(){let i=new WeakMap,m=50+Math.floor(Math.random()*1e3),d=50+Math.floor(Math.random()*2e3);function y(e,n,t,r){return{x:e,y:n,clientX:e,clientY:n,layerX:e,layerY:n,offsetX:e-1,offsetY:n-1,pageX:e,pageY:n,screenX:t+e,screenY:r+n}}function w(e,n){i.get(e).filter(([r])=>r===n.type).forEach(([r,o])=>{o(n)})}let b={click:({selector:e,offset:n,screenOffset:t,events:r})=>{let o=document.querySelector(e);if(!o||!i.has(o))return;let a=o.getBoundingClientRect(),u=n?n[0]:Math.floor(Math.random()*a.width),s=n?n[1]:Math.floor(Math.random()*a.height),p=t?t[0]:m,c=t?t[1]:d,l=r??["click"];for(let f of l){let M=h("PointerEvent",f,{...y(u,s,p,c),composed:!0,pointerId:1,pointerType:"mouse",srcElement:o,target:o},{target:o});w(o,M)}},mousedata:({data:e,timeOffset:n})=>{let t=Date.now,r=0;Date.now=()=>r;let o=[["mm","mousemove"],["md","mousedown"],["mu","mouseup"]],a=document.body;o.forEach(([u,s])=>{e[u].forEach(([p,c,l])=>{let f=h("MouseEvent",s,{...y(p,c,0,0),composed:!0,pointerId:1,pointerType:"mouse",srcElement:a,target:a},{target:a,timestamp:n+l-performance.timeOrigin});r=Math.floor(n+l),w(a,f)})}),Date.now=t}};function h(e,n,t,r){{let o=new window[e](n,t),a={get(u,s,p){if(s==="isTrusted")return!0;if(s in r)return r[s];let c=o[s];return c instanceof Function?c.bind(o):c}};return new Proxy(o,a)}}function v(e){typeof e=="string"&&(e=JSON.parse(e)),b[e.action](e)}function k(e,n){i.has(e)||i.set(e,[]),i.get(e).push(n)}{let e=Element.prototype;e.addEventListener=new Proxy(e.addEventListener,{apply(n,t,r){return k(t,r),n.apply(t,r)}})}return v}function E(){let i=g();addEventListener("message",m=>{let d=m.data;typeof d!="object"||d.source!=="nopecha"||(m.stopImmediatePropagation(),i(d))})}E();})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/128.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/128g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/128g.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/16.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/16g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/16g.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/32.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/32g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/32g.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/48.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/48g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/icon/48g.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "update_url": "https://clients2.google.com/service/update2/crx", 3 | "name":"NopeCHA: CAPTCHA Solver","version":"0.4.9","description":"Automatically solve reCAPTCHA, hCaptcha, FunCAPTCHA, AWS WAF, and text CAPTCHA using AI.","content_scripts":[{"matches":["*://*.hcaptcha.com/captcha/*"],"js":["eventhook.js","captcha/hcaptcha.js"],"run_at":"document_start","all_frames":true},{"matches":["*://*.google.com/recaptcha/*","*://*.recaptcha.net/recaptcha/*"],"js":["eventhook.js","captcha/recaptcha.js"],"run_at":"document_start","all_frames":true},{"matches":["*://*.arkoselabs.com/fc/*","*://*.funcaptcha.com/fc/*","*://*/fc/assets/*"],"js":["captcha/funcaptcha.js"],"run_at":"document_end","all_frames":true},{"matches":["*://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/*","*://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/g/turnstile/if/ov2/av0/*"],"js":["eventhook.js","captcha/turnstile.js"],"run_at":"document_start","all_frames":true},{"matches":["*://nopecha.com/setup"],"js":["pages/setup.js"],"run_at":"document_end","all_frames":false},{"matches":["*://nopecha.com/integrate"],"js":["pages/integrate.js"],"run_at":"document_end","all_frames":true},{"matches":["*://nopecha.com/demo/funcaptcha"],"js":["pages/funcaptcha-demo.js"],"run_at":"document_end","all_frames":false},{"matches":[""],"js":["captcha/awscaptcha.js","captcha/textcaptcha.js","captcha/perimeterx.js"],"run_at":"document_end","match_about_blank":true,"all_frames":true}],"icons":{"16":"icon/16.png","32":"icon/32.png","48":"icon/48.png","128":"icon/128.png"},"manifest_version":3,"permissions":["declarativeNetRequest","storage","scripting"],"background":{"service_worker":"background.js","type":"module"},"action":{"default_title":"NopeCHA: CAPTCHA Solver","default_icon":"icon/16.png","default_popup":"popup.html"},"host_permissions":[""],"key":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlWiyXSK0GK0nDwOfOJ2zUvRv99E2XU6LnR67zKE5RjM2icff7Cwmo6nR5i+4UukShIyEaDdQsbC+vyTpDeaJMn+bNphPYjQxGY6spIk3KV1h71Jj0dSUOYUwGrViKg3LnC4LKtENYOsbIxTmMw8JG4oH1hU1tY4KlnSzcqiwTaDLTP0X7MVdDK0WPOyypNlkL7v1HWMjPZa32EudqcrWub/EMpMFuSugTyIu8dHaAQhW13RkU77BiMRoZfZYxbcED48YPmZS8qi3KOrymjOTWCJeDMjwy/MLCqrwhjoG1Y5jDXHFbxNUPxEJYw9mxxPTN+asraML9tywlLuzZluHwwIDAQAB","minimum_chrome_version":"100.0","version_name":"v0.4.9"} -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/pages/integrate.js: -------------------------------------------------------------------------------- 1 | (()=>{var c=chrome;var o="https://api.nopecha.com",e="https://www.nopecha.com",n="https://developers.nopecha.com",i={doc:{url:n,automation:{url:`${n}/guides/extension_advanced/#automation-build`}},api:{url:o,recognition:{url:`${o}/recognition`},status:{url:`${o}/status`}},www:{url:e,annoucement:{url:`${e}/json/announcement.json`},demo:{url:`${e}/demo`,hcaptcha:{url:`${e}/demo/hcaptcha`},recaptcha:{url:`${e}/demo/recaptcha`},funcaptcha:{url:`${e}/demo/funcaptcha`},awscaptcha:{url:`${e}/demo/awscaptcha`},turnstile:{url:`${e}/demo/turnstile`},textcaptcha:{url:`${e}/demo/textcaptcha`},perimeterx:{url:`${e}/demo/perimeterx`}},manage:{url:`${e}/manage`},pricing:{url:`${e}/pricing`},setup:{url:`${e}/setup`}},discord:{url:`${e}/discord`},github:{url:`${e}/github`,release:{url:`${e}/github/release`}}};function a(r){if(document.readyState!=="loading")setTimeout(r,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),r()},addEventListener("DOMContentLoaded",t)}}function u(){document.documentElement.setAttribute("installed","yes"),document.documentElement.setAttribute("data",JSON.stringify({version:c.runtime.getManifest().version}))}a(u);})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/pages/setup.js: -------------------------------------------------------------------------------- 1 | (()=>{var g=chrome;var l="https://api.nopecha.com",r="https://www.nopecha.com",h="https://developers.nopecha.com",T={doc:{url:h,automation:{url:`${h}/guides/extension_advanced/#automation-build`}},api:{url:l,recognition:{url:`${l}/recognition`},status:{url:`${l}/status`}},www:{url:r,annoucement:{url:`${r}/json/announcement.json`},demo:{url:`${r}/demo`,hcaptcha:{url:`${r}/demo/hcaptcha`},recaptcha:{url:`${r}/demo/recaptcha`},funcaptcha:{url:`${r}/demo/funcaptcha`},awscaptcha:{url:`${r}/demo/awscaptcha`},turnstile:{url:`${r}/demo/turnstile`},textcaptcha:{url:`${r}/demo/textcaptcha`},perimeterx:{url:`${r}/demo/perimeterx`}},manage:{url:`${r}/manage`},pricing:{url:`${r}/pricing`},setup:{url:`${r}/setup`}},discord:{url:`${r}/discord`},github:{url:`${r}/github`,release:{url:`${r}/github/release`}}};function f(e){let t=("6146a541f7b2046020e84d44aa2e1e120f2ad8b75ac9b6fc236f65f737a7006f"+e).split("").map(o=>o.charCodeAt(0));return y(t)}var b=new Uint32Array(256);for(let e=256;e--;){let t=e;for(let o=8;o--;)t=t&1?3988292384^t>>>1:t>>>1;b[e]=t}function y(e){let t=-1;for(let o of e)t=t>>>8^b[t&255^o];return(t^-1)>>>0}async function x(e,t){let o=""+[+new Date,performance.now(),Math.random()],[s,n]=await new Promise(c=>{g.runtime.sendMessage([o,e,...t],c)});if(s===f(o))return n}function m(e){if(document.readyState!=="loading")setTimeout(e,0);else{let t;t=()=>{removeEventListener("DOMContentLoaded",t),e()},addEventListener("DOMContentLoaded",t)}}[...document.body.children].forEach(e=>e.remove());function i(e,t,o={}){let s=document.createElement(e);return o&&Object.entries(o).forEach(([n,c])=>s[n]=c),t.appendChild(s),s}function $(){i("h1",document.body,{innerText:"Invalid URL."}),i("h2",document.body,{innerText:"Please set the URL hash and reload the page."}),i("p",document.body,{innerText:"Example: https://nopecha.com/setup#TESTKEY123"})}function w(e){return/^(true|false)$/.test(e)?e==="true":/^\d+$/.test(e)?+e:e}function _(){let e="NopeCHA Settings Import",t=document.querySelector("title");document.title!==e&&t&&(t.innerText=e);let o=document.location.hash.substring(1);if(!o)return $();let s=o.split("|"),n=Object.fromEntries(s.map(a=>a.includes("=")?a.split("="):["key",a]).map(([a,d])=>[a,w(d)]));if("disabled_hosts"in n){let a=""+n.disabled_hosts;a===""?n.disabled_hosts=[]:decodeURIComponent(a).startsWith("[")?n.disabled_hosts=JSON.parse(decodeURIComponent(a)):n.disabled_hosts=a.split(",")}"key"in n&&n.key.includes(",")&&(n.keys=n.key.split(","),delete n.key),console.log(n),i("h2",document.body,{innerText:"Imported following settings:"});let c=i("table",document.body),u=i("tr",c);i("th",u,{innerText:"Name"}),i("th",u,{innerText:"Value"}),Object.entries(n).forEach(([a,d])=>{let p=i("tr",c);i("td",p,{innerText:a}),i("td",p,{innerText:JSON.stringify(d)})}),i("h2",document.body,{innerText:"Import URL:"}),i("a",document.body,{innerText:location.href,href:location.href,style:"word-wrap: break-word"}),x("settings::update",[n])}m(_);})(); 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NopeCHA 7 | 8 | 9 | 10 | 11 |

12 | If you can see this, please make sure popup.js is not 13 | corrupted. 14 |

15 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/NopeCHA-CAPTCHA-Solver/setup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NopeCHA 7 | 8 | 9 | 10 |

11 | If you can see this, please make sure setup.js is not 12 | corrupted. 13 |

14 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/__init__.py -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/Packaged.capsolver-automatic.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/Packaged.capsolver-automatic.zip -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/_locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "Captcha Solver: Auto Recognition and Bypass" 4 | }, 5 | "extDescription": { 6 | "message": "Capsolver Solver plugin allows you to automatically solve CAPTCHAs found on any webpage." 7 | }, 8 | "extShortName": { 9 | "message": "Captcha solver" 10 | }, 11 | "optionsPageTitle": { 12 | "message": "Capsolver Extension Settings" 13 | }, 14 | "accountSettings": { 15 | "message": "Account Settings:" 16 | }, 17 | "apiKey": { 18 | "message": "API-KEY:" 19 | }, 20 | "connect": { 21 | "message": "Connect" 22 | }, 23 | "doNotHaveApiKey": { 24 | "message": "Do not have API-KEY?" 25 | }, 26 | "createAccountToGetIt": { 27 | "message": "Create account to get it.", 28 | "placeholders": { 29 | "link": { 30 | "content": "$1" 31 | } 32 | } 33 | }, 34 | "generalSettings": { 35 | "message": "General settings:" 36 | }, 37 | "enablePlugin": { 38 | "message": "Enable plugin" 39 | }, 40 | "submitFormsAutomatically": { 41 | "message": "Submit forms automatically" 42 | }, 43 | "settingsLink": { 44 | "message": "Settings" 45 | }, 46 | "manualLink": { 47 | "message": "Manual" 48 | }, 49 | "enabledSolveAutomatically": { 50 | "message": "Enabled / Solve automatically" 51 | }, 52 | "minScore": { 53 | "message": "min. score:" 54 | }, 55 | "haveAnyQuestions": { 56 | "message": "Have any questions/suggestions?" 57 | }, 58 | "contactUs": { 59 | "message": "Contact us: $email$", 60 | "placeholders": { 61 | "email": { 62 | "content": "$1" 63 | } 64 | } 65 | }, 66 | "balance": { 67 | "message": "Balance" 68 | }, 69 | "login": { 70 | "message": "Login" 71 | }, 72 | "logout": { 73 | "message": "Logout" 74 | }, 75 | "accountSuccessfullyConnected": { 76 | "message": "Account successfully connected!" 77 | }, 78 | "solveWithCapsolver": { 79 | "message": "Solve with Capsolver" 80 | }, 81 | "solving": { 82 | "message": "Solving..." 83 | }, 84 | "solved": { 85 | "message": "Captcha solved!" 86 | }, 87 | "delay": { 88 | "message": "Delay" 89 | }, 90 | "seconds": { 91 | "message": "seconds" 92 | }, 93 | "ifErrorRepeat": { 94 | "message": "If error happens, repeat" 95 | }, 96 | "times": { 97 | "message": "times" 98 | }, 99 | "proxySettings": { 100 | "message": "Proxy settings" 101 | }, 102 | "useProxy": { 103 | "message": "Use proxy" 104 | }, 105 | "proxyType": { 106 | "message": "Proxy type" 107 | }, 108 | "images": { 109 | "message": "Images" 110 | }, 111 | "markAsCaptchaSource": { 112 | "message": "Mark as captcha source" 113 | }, 114 | "putCaptchaAnswerHere": { 115 | "message": "Put captcha answer here" 116 | }, 117 | "normalManual": { 118 | "message": "Location of image with captcha is saved. Now, please choose where to put answer." 119 | }, 120 | "autoSubmitRules": { 121 | "message": "AutoSubmit rules" 122 | }, 123 | "autoSubmitDescription": { 124 | "message": "By default, \"AutoSubmit\" feature submits form which contains captcha answer field. If something else must be done after captcha is solved, for example some button must be clicked, please define it here:" 125 | }, 126 | "autoSubmitNoRules": { 127 | "message": "No rules added yet..." 128 | }, 129 | "autoSubmitCreateNewRule": { 130 | "message": "Create new rule" 131 | }, 132 | "autoSubmitAlertFormOpened": { 133 | "message": "Please save or cancel previously opened form first!" 134 | }, 135 | "autoSubmitAlertUrlRequired": { 136 | "message": "URL pattern is required!" 137 | }, 138 | "autoSubmitAlertUrlInvalid": { 139 | "message": "URL pattern must be valid regular expression!" 140 | }, 141 | "autoSubmitAlertCodeRequired": { 142 | "message": "Code is required!" 143 | }, 144 | "autoSubmitConfirmDelete": { 145 | "message": "Delete rule" 146 | }, 147 | "autoSubmitPlaceholderUrl": { 148 | "message": "URL pattern (regexp), for example:" 149 | }, 150 | "autoSubmitPlaceholderCode": { 151 | "message": "Sequence of actions to execute, for example:" 152 | }, 153 | "save": { 154 | "message": "Save" 155 | }, 156 | "cancel": { 157 | "message": "Cancel" 158 | }, 159 | "edit": { 160 | "message": "Edit" 161 | }, 162 | "delete": { 163 | "message": "Delete" 164 | }, 165 | "blackListDomain": { 166 | "message": "Domain blacklist" 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/_locales/es/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "Captcha Solver: Auto Evitar" 4 | }, 5 | "extDescription": { 6 | "message": "La extensión para resolver automáticalmente los CAPTCHAs en cualqer página web." 7 | }, 8 | "extShortName": { 9 | "message": "Captcha Solver" 10 | }, 11 | "optionsPageTitle": { 12 | "message": "Ajustes de Capsolver Extensión" 13 | }, 14 | "accountSettings": { 15 | "message": "Ajustes de la cuenta" 16 | }, 17 | "apiKey": { 18 | "message": "API-KEY:" 19 | }, 20 | "connect": { 21 | "message": "Conectar" 22 | }, 23 | "doNotHaveApiKey": { 24 | "message": "¿No tiene API-KEY?" 25 | }, 26 | "createAccountToGetIt": { 27 | "message": "Crea una cuenta para obtenerlo.", 28 | "placeholders": { 29 | "link": { 30 | "content": "$1" 31 | } 32 | } 33 | }, 34 | "generalSettings": { 35 | "message": "Ajustes generales:" 36 | }, 37 | "enablePlugin": { 38 | "message": "Habilitar extensión" 39 | }, 40 | "submitFormsAutomatically": { 41 | "message": "Enviar formularios automáticalmente" 42 | }, 43 | "settingsLink": { 44 | "message": "Ajustes" 45 | }, 46 | "manualLink": { 47 | "message": "Manual" 48 | }, 49 | "enabledSolveAutomatically": { 50 | "message": "Activado / Resolver automáticalmente" 51 | }, 52 | "minScore": { 53 | "message": "min. score:" 54 | }, 55 | "haveAnyQuestions": { 56 | "message": "¿Tiene preguntas o sugerencias?" 57 | }, 58 | "contactUs": { 59 | "message": "Contactenos: $email$", 60 | "placeholders": { 61 | "email": { 62 | "content": "$1" 63 | } 64 | } 65 | }, 66 | "balance": { 67 | "message": "Saldo" 68 | }, 69 | "login": { 70 | "message": "Iniciar sesión" 71 | }, 72 | "logout": { 73 | "message": "Cerrar sesión" 74 | }, 75 | "accountSuccessfullyConnected": { 76 | "message": "¡La cuenta conectada con éxito!" 77 | }, 78 | "solveWithCapsolver": { 79 | "message": "Resolver con Capsolver" 80 | }, 81 | "solving": { 82 | "message": "Resolviendo..." 83 | }, 84 | "solved": { 85 | "message": "Captcha está resuelta!" 86 | }, 87 | "delay": { 88 | "message": "Retraso" 89 | }, 90 | "seconds": { 91 | "message": "segundos" 92 | }, 93 | "ifErrorRepeat": { 94 | "message": "En caso de error, repetir" 95 | }, 96 | "times": { 97 | "message": "veces" 98 | }, 99 | "proxySettings": { 100 | "message": "Ajustes de proxy" 101 | }, 102 | "useProxy": { 103 | "message": "Usar proxy" 104 | }, 105 | "proxyType": { 106 | "message": "Tipo de proxy" 107 | }, 108 | "images": { 109 | "message": "Imagenes" 110 | }, 111 | "markAsCaptchaSource": { 112 | "message": "Marcar como fuente de captcha" 113 | }, 114 | "putCaptchaAnswerHere": { 115 | "message": "Pon la respuesta de captcha aquí" 116 | }, 117 | "normalManual": { 118 | "message": "La ubicación de la imagen de captcha fue guardado. Ahora, elija dónde poner la respuesta." 119 | }, 120 | "autoSubmitRules": { 121 | "message": "Reglas de envío automático" 122 | }, 123 | "autoSubmitDescription": { 124 | "message": "De forma predeterminada, la función \"AutoSubmit\" envía un formulario que contiene un campo de respuesta captcha. Si se debe hacer algo más después de resolver el captcha, por ejemplo, se debe hacer clic en algún botón, defínalo aquí:" 125 | }, 126 | "autoSubmitNoRules": { 127 | "message": "Aún no se agregaron reglas..." 128 | }, 129 | "autoSubmitCreateNewRule": { 130 | "message": "Crear nueva regla" 131 | }, 132 | "autoSubmitAlertFormOpened": { 133 | "message": "¡Guarde o cancele primero el formulario abierto anteriormente!" 134 | }, 135 | "autoSubmitAlertUrlRequired": { 136 | "message": "¡Se requiere un patrón de URL!" 137 | }, 138 | "autoSubmitAlertUrlInvalid": { 139 | "message": "El patrón de URL debe ser una expresión regular válida." 140 | }, 141 | "autoSubmitAlertCodeRequired": { 142 | "message": "¡Se requiere código!" 143 | }, 144 | "autoSubmitConfirmDelete": { 145 | "message": "Eliminar regla" 146 | }, 147 | "autoSubmitPlaceholderUrl": { 148 | "message": "Patrón de URL (regex), por ejemplo:" 149 | }, 150 | "autoSubmitPlaceholderCode": { 151 | "message": "Secuencia de acciones a ejecutar, por ejemplo:" 152 | }, 153 | "save": { 154 | "message": "Ahorrar" 155 | }, 156 | "cancel": { 157 | "message": "Cancelar" 158 | }, 159 | "edit": { 160 | "message": "Editar" 161 | }, 162 | "delete": { 163 | "message": "Borrar" 164 | }, 165 | "blackListDomain": { 166 | "message": "Lista negra de dominio" 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/_locales/ru/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "Captcha Solver: Обход и Авто Ввод Капчи" 4 | }, 5 | "extDescription": { 6 | "message": "Этот плагин помогает решать капчи на страницах сайтов." 7 | }, 8 | "extShortName": { 9 | "message": "Captcha Solver" 10 | }, 11 | "optionsPageTitle": { 12 | "message": "Настройки расширения Capsolver" 13 | }, 14 | "accountSettings": { 15 | "message": "Настройки аккаунта:" 16 | }, 17 | "apiKey": { 18 | "message": "API-ключ:" 19 | }, 20 | "connect": { 21 | "message": "Подключить" 22 | }, 23 | "doNotHaveApiKey": { 24 | "message": "Нет API-ключа?" 25 | }, 26 | "createAccountToGetIt": { 27 | "message": "Создайте аккаунт чтобы его получить.", 28 | "placeholders": { 29 | "link": { 30 | "content": "$1" 31 | } 32 | } 33 | }, 34 | "generalSettings": { 35 | "message": "Общие настройки:" 36 | }, 37 | "enablePlugin": { 38 | "message": "Включить плагин" 39 | }, 40 | "submitFormsAutomatically": { 41 | "message": "Отправлять формы автоматически" 42 | }, 43 | "settingsLink": { 44 | "message": "Настройки" 45 | }, 46 | "manualLink": { 47 | "message": "Документация" 48 | }, 49 | "enabledSolveAutomatically": { 50 | "message": "Включено / Решать автоматически" 51 | }, 52 | "minScore": { 53 | "message": "мин. score:" 54 | }, 55 | "haveAnyQuestions": { 56 | "message": "Есть вопросы/предложения?" 57 | }, 58 | "contactUs": { 59 | "message": "Дайте нам знать: $email$", 60 | "placeholders": { 61 | "email": { 62 | "content": "$1" 63 | } 64 | } 65 | }, 66 | "balance": { 67 | "message": "Баланс" 68 | }, 69 | "login": { 70 | "message": "Войти" 71 | }, 72 | "logout": { 73 | "message": "Выход" 74 | }, 75 | "accountSuccessfullyConnected": { 76 | "message": "Аккаунт успешно подключен!" 77 | }, 78 | "solveWithCapsolver": { 79 | "message": "Решить с Capsolver" 80 | }, 81 | "solving": { 82 | "message": "Решается..." 83 | }, 84 | "solved": { 85 | "message": "Капча решена!" 86 | }, 87 | "delay": { 88 | "message": "Задержка" 89 | }, 90 | "seconds": { 91 | "message": "секунд" 92 | }, 93 | "ifErrorRepeat": { 94 | "message": "В случае ошибки, повторить" 95 | }, 96 | "times": { 97 | "message": "раз" 98 | }, 99 | "proxySettings": { 100 | "message": "Настройки прокси" 101 | }, 102 | "useProxy": { 103 | "message": "Использовать прокси" 104 | }, 105 | "proxyType": { 106 | "message": "Тип прокси" 107 | }, 108 | "images": { 109 | "message": "Изображения" 110 | }, 111 | "markAsCaptchaSource": { 112 | "message": "Решать эту капчу" 113 | }, 114 | "putCaptchaAnswerHere": { 115 | "message": "Вставить ответ на капчу сюда" 116 | }, 117 | "normalManual": { 118 | "message": "Расположение изображения с капчей сохранено. Теперь укажите поле, куда вставить ответ." 119 | }, 120 | "autoSubmitRules": { 121 | "message": "Правила автоотправки форм" 122 | }, 123 | "autoSubmitDescription": { 124 | "message": "По умолчанию, функция \"Автоотправка\", после получения ответа, сабмитит форму, в которой находиться капча. Если после успешного решения капчи нужно сделать что-то другое, например нажать какую-то кнопку, укажите это здесь:" 125 | }, 126 | "autoSubmitNoRules": { 127 | "message": "Еще не добавлено ни одного правила..." 128 | }, 129 | "autoSubmitCreateNewRule": { 130 | "message": "Создать новое правило" 131 | }, 132 | "autoSubmitAlertFormOpened": { 133 | "message": "Please save or cancel previously opened form first!" 134 | }, 135 | "autoSubmitAlertUrlRequired": { 136 | "message": "URL шаблон не заполнен!" 137 | }, 138 | "autoSubmitAlertUrlInvalid": { 139 | "message": "URL шаблон должен быть валидным regexp!" 140 | }, 141 | "autoSubmitAlertCodeRequired": { 142 | "message": "Код не заполнен!" 143 | }, 144 | "autoSubmitConfirmDelete": { 145 | "message": "Удалить правило" 146 | }, 147 | "autoSubmitPlaceholderUrl": { 148 | "message": "URL шаблон (regexp), например:" 149 | }, 150 | "autoSubmitPlaceholderCode": { 151 | "message": "Последовательность действий для выполнения, например:" 152 | }, 153 | "save": { 154 | "message": "Сохранить" 155 | }, 156 | "cancel": { 157 | "message": "Отменить" 158 | }, 159 | "edit": { 160 | "message": "Изменить" 161 | }, 162 | "delete": { 163 | "message": "Удалить" 164 | }, 165 | "blackListDomain": { 166 | "message": "Черный список доменов" 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/_locales/zh/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extName": { 3 | "message": "Captcha Solver: Auto Recognition and Bypass" 4 | }, 5 | "extDescription": { 6 | "message": "该插件拓展程序有助于解决网站页面上的验证码。无论处于什么网页,该拓展程序都能帮助您自动识别网页上的验证码" 7 | }, 8 | "extShortName": { 9 | "message": "Captcha Solver" 10 | }, 11 | "optionsPageTitle": { 12 | "message": "设置2CAPTCHA 拓展程序" 13 | }, 14 | "accountSettings": { 15 | "message": "设置账户:" 16 | }, 17 | "apiKey": { 18 | "message": "API 密钥:" 19 | }, 20 | "connect": { 21 | "message": "联系" 22 | }, 23 | "doNotHaveApiKey": { 24 | "message": "没有API密钥?" 25 | }, 26 | "createAccountToGetIt": { 27 | "message": "创建一个账户 可获取API 密钥.", 28 | "placeholders": { 29 | "link": { 30 | "content": "$1" 31 | } 32 | } 33 | }, 34 | "generalSettings": { 35 | "message": "一般设置:" 36 | }, 37 | "enablePlugin": { 38 | "message": "启用插件" 39 | }, 40 | "submitFormsAutomatically": { 41 | "message": "自动提交表格" 42 | }, 43 | "settingsLink": { 44 | "message": "設置" 45 | }, 46 | "manualLink": { 47 | "message": "手動的" 48 | }, 49 | "enabledSolveAutomatically": { 50 | "message": "启用/自动解决" 51 | }, 52 | "minScore": { 53 | "message": "最小分值:" 54 | }, 55 | "haveAnyQuestions": { 56 | "message": "有任何问题或者建议?" 57 | }, 58 | "contactUs": { 59 | "message": "联系我们: $email$", 60 | "placeholders": { 61 | "email": { 62 | "content": "$1" 63 | } 64 | } 65 | }, 66 | "balance": { 67 | "message": "余额" 68 | }, 69 | "login": { 70 | "message": "登陆" 71 | }, 72 | "logout": { 73 | "message": "登出" 74 | }, 75 | "accountSuccessfullyConnected": { 76 | "message": "账户关联成功!" 77 | }, 78 | "solveWithCapsolver": { 79 | "message": "使用Capsolver解决" 80 | }, 81 | "solving": { 82 | "message": "正在解决..." 83 | }, 84 | "solved": { 85 | "message": "验证码解决成功啦!" 86 | }, 87 | "delay": { 88 | "message": "延迟" 89 | }, 90 | "seconds": { 91 | "message": "秒" 92 | }, 93 | "ifErrorRepeat": { 94 | "message": "如有错误,请重复" 95 | }, 96 | "times": { 97 | "message": "时间" 98 | }, 99 | "proxySettings": { 100 | "message": "Proxy设置" 101 | }, 102 | "useProxy": { 103 | "message": "使用代理服务器" 104 | }, 105 | "proxyType": { 106 | "message": "代理类型" 107 | }, 108 | "images": { 109 | "message": "图片" 110 | }, 111 | "markAsCaptchaSource": { 112 | "message": "标记为验证码来源" 113 | }, 114 | "putCaptchaAnswerHere": { 115 | "message": "把验证码答案放在这里" 116 | }, 117 | "normalManual": { 118 | "message": "带有验证码的图像的位置被保存。 现在选择把答案放在哪里." 119 | }, 120 | "autoSubmitRules": { 121 | "message": "自动提交规则" 122 | }, 123 | "autoSubmitDescription": { 124 | "message": "默认情况下,“自动提交”功能提交包含验证码答案字段的表单。 如果验证码解决后还必须做其他事情,例如必须点击某个按钮,请在此处定义:" 125 | }, 126 | "autoSubmitNoRules": { 127 | "message": "还没有添加规则..." 128 | }, 129 | "autoSubmitCreateNewRule": { 130 | "message": "创建新规则" 131 | }, 132 | "autoSubmitAlertFormOpened": { 133 | "message": "请先保存或取消之前打开的表格!" 134 | }, 135 | "autoSubmitAlertUrlRequired": { 136 | "message": "网址格式为必填项!" 137 | }, 138 | "autoSubmitAlertUrlInvalid": { 139 | "message": "URL 模式必须是有效的正则表达式!" 140 | }, 141 | "autoSubmitAlertCodeRequired": { 142 | "message": "需要代码!" 143 | }, 144 | "autoSubmitConfirmDelete": { 145 | "message": "删除规则" 146 | }, 147 | "autoSubmitPlaceholderUrl": { 148 | "message": "URL 模式(regexp),例如:" 149 | }, 150 | "autoSubmitPlaceholderCode": { 151 | "message": "要执行的操作序列,例如:" 152 | }, 153 | "save": { 154 | "message": "节省" 155 | }, 156 | "cancel": { 157 | "message": "取消" 158 | }, 159 | "edit": { 160 | "message": "编辑" 161 | }, 162 | "delete": { 163 | "message": "删除" 164 | }, 165 | "blackListDomain": { 166 | "message": "域名黑名單" 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/config.js: -------------------------------------------------------------------------------- 1 | export const defaultConfig = { 2 | // API key 3 | apiKey: 'test_key', 4 | 5 | // Your Developer appId, Apply in dashboard's developer section 6 | appId: '', 7 | 8 | // Is the extension enabled by default or not 9 | useCapsolver: true, 10 | 11 | // Solve captcha manually 12 | manualSolving: false, 13 | 14 | // Captcha solved callback function name 15 | solvedCallback: 'captchaSolvedCallback', 16 | 17 | // Use proxy or not 18 | // If useProxy is true, then proxyType, hostOrIp, port, proxyLogin, proxyPassword are required 19 | useProxy: false, 20 | proxyType: 'http', 21 | hostOrIp: '', 22 | port: '', 23 | proxyLogin: '', 24 | proxyPassword: '', 25 | 26 | enabledForBlacklistControl: false, // Use blacklist control 27 | blackUrlList: [], // Blacklist URL list 28 | 29 | // Is captcha enabled by default or not 30 | enabledForRecaptcha: true, 31 | enabledForRecaptchaV3: true, 32 | enabledForHCaptcha: true, 33 | enabledForFunCaptcha: true, 34 | enabledForImageToText: true, 35 | enabledForAwsCaptcha: true, 36 | 37 | // Task type: click or token 38 | reCaptchaMode: 'click', 39 | hCaptchaMode: 'click', 40 | 41 | // Delay before solving captcha 42 | reCaptchaDelayTime: 0, 43 | hCaptchaDelayTime: 0, 44 | textCaptchaDelayTime: 0, 45 | awsDelayTime: 0, 46 | 47 | // Number of repeated solutions after an error 48 | reCaptchaRepeatTimes: 10, 49 | reCaptcha3RepeatTimes: 10, 50 | hCaptchaRepeatTimes: 10, 51 | funCaptchaRepeatTimes: 10, 52 | textCaptchaRepeatTimes: 10, 53 | awsRepeatTimes: 10, 54 | 55 | // ReCaptcha V3 task type: ReCaptchaV3TaskProxyLess or ReCaptchaV3M1TaskProxyLess 56 | reCaptcha3TaskType: 'ReCaptchaV3TaskProxyLess', 57 | 58 | textCaptchaSourceAttribute: 'capsolver-image-to-text-source', // ImageToText source img's attribute name 59 | textCaptchaResultAttribute: 'capsolver-image-to-text-result', // ImageToText result element's attribute name 60 | }; 61 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/content.css: -------------------------------------------------------------------------------- 1 | /* Global CSS used within your BEX. This is not preprocessed so this has to be pure CSS. */ 2 | .capsolver-solver { 3 | display: flex; 4 | box-sizing: border-box; 5 | max-width: 304px; 6 | margin-left: auto !important; 7 | margin-right: auto !important; 8 | margin-top: 5px; 9 | margin-bottom: 5px; 10 | border: 2px solid #06201B; 11 | border-radius: 8px; 12 | background-color: #fff; 13 | /*background-color: #9ceedd;*/ 14 | transition: all 0.2s linear; 15 | } 16 | 17 | .capsolver-solver:hover { 18 | box-shadow: 4px 4px 0 #000000; 19 | cursor: pointer; 20 | } 21 | 22 | .capsolver-solver[data-state=solved], 23 | .capsolver-solver[data-state=solving], 24 | .capsolver-solver[data-state=ready] { 25 | /*background: linear-gradient(0deg, #232323 0%, #4b4b4b 100%);*/ 26 | background-color: #cce8e1; 27 | cursor: not-allowed; 28 | color: #91be88; 29 | } 30 | 31 | .capsolver-solver[data-state=ready] { 32 | cursor: pointer; 33 | } 34 | 35 | .capsolver-solver[data-state=error] { 36 | background-color: #BA1A1A; 37 | color: #fff; 38 | } 39 | 40 | .capsolver-solver[data-state=error]:hover { 41 | background-color: #f6c0c0; 42 | color: #BA1A1A; 43 | } 44 | 45 | .capsolver-solver-image { 46 | width: 38px; 47 | flex: 0 0 38px; 48 | /*border-right: 1px solid #00bcbd !important;*/ 49 | } 50 | 51 | .capsolver-solver-image img { 52 | display: block; 53 | margin: 8px auto !important; 54 | width: 18px !important; 55 | height: 18px !important; 56 | } 57 | 58 | .capsolver-solver[data-state=solved] .capsolver-solver-image, 59 | .capsolver-solver[data-state=solving] .capsolver-solver-image, 60 | .capsolver-solver[data-state=ready] .capsolver-solver-image { 61 | background-color: #191C1B; 62 | } 63 | 64 | .capsolver-solver[data-state=error] .capsolver-solver-image { 65 | background-color: #191C1B; 66 | } 67 | 68 | @keyframes blink { 69 | 50% { 70 | opacity: .2; 71 | } 72 | } 73 | 74 | .capsolver-solver-info { 75 | padding: 6px 8px !important; 76 | word-break: break-word; 77 | font-family: sans-serif; 78 | font-size: 14px; 79 | line-height: 22px; 80 | color: inherit; 81 | } 82 | 83 | .capsolver-solver[data-state=solved] .capsolver-solver-info, 84 | .capsolver-solver[data-state=solving] .capsolver-solver-info, 85 | .capsolver-solver[data-state=ready] .capsolver-solver-info { 86 | color: #000000; 87 | } 88 | 89 | .grecaptcha-badge .capsolver-solver { 90 | text-align: left; 91 | margin-bottom: 0; 92 | } 93 | 94 | .capsolver-solver-hcaptcha { 95 | margin: 0 auto; 96 | } 97 | 98 | .capsolver-solver-hcaptcha-helper { 99 | display: none !important; 100 | } 101 | 102 | .capsolver-solver-geetest { 103 | margin: 5px auto 0 auto; 104 | } 105 | 106 | .capsolver-solver-keycaptcha { 107 | margin: 5px auto 0 auto; 108 | width: 300px; 109 | } 110 | 111 | .capsolver-solver-keycaptcha-working { 112 | opacity: 0.4; 113 | cursor: not-allowed; 114 | } 115 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/assets/images/logo.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/images/logo_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/assets/images/logo_solved.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/inject/inject-aws.js: -------------------------------------------------------------------------------- 1 | const domain = 'awswaf.com'; 2 | const awsListeningList = [ 3 | '/problem', 4 | '/verify', 5 | ]; 6 | 7 | (function () { 8 | let origFetch = window.fetch; 9 | window.fetch = async function (...args) { 10 | const _url = args[0]; 11 | const response = await origFetch(...args); 12 | 13 | response 14 | .clone() 15 | .blob() 16 | .then(async data => { 17 | if (_url.indexOf(domain) === -1) return; 18 | 19 | const domainIndex = _url.indexOf(domain); 20 | const isInList = awsListeningList.some(url => { 21 | if (_url.indexOf(url) === -1) return false; 22 | const urlIndex = _url.indexOf(url); 23 | 24 | if (domainIndex > urlIndex) return false; 25 | 26 | return true; 27 | }); 28 | if (isInList) { 29 | window.postMessage( 30 | { 31 | type: 'fetch', 32 | data: await data.text(), 33 | url: _url, 34 | }, 35 | '*', 36 | ); 37 | } 38 | }) 39 | .catch(err => { 40 | console.log(err); 41 | }); 42 | 43 | return response; 44 | }; 45 | })(); 46 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/inject/inject-funcaptcha.js: -------------------------------------------------------------------------------- 1 | const funcaptchaListeningList = [ 2 | '/gfct' 3 | ]; 4 | 5 | (function (xhr) { 6 | var XHR = XMLHttpRequest.prototype; 7 | 8 | var open = XHR.open; 9 | var send = XHR.send; 10 | 11 | XHR.open = function (method, url) { 12 | this._method = method; 13 | this._url = url; 14 | return open.apply(this, arguments); 15 | }; 16 | 17 | XHR.send = function (postData) { 18 | const _url = this._url; 19 | this.addEventListener('load', function () { 20 | const isInList = funcaptchaListeningList.some(url => _url.indexOf(url) !== -1); 21 | if (isInList) { 22 | window.postMessage({ type: 'xhr', data: this.response, url: _url }, '*'); 23 | } 24 | }); 25 | 26 | return send.apply(this, arguments); 27 | }; 28 | })(XMLHttpRequest); 29 | 30 | (function () { 31 | let origFetch = window.fetch; 32 | window.fetch = async function (...args) { 33 | const _url = args[0]; 34 | const response = await origFetch(...args); 35 | 36 | response 37 | .clone() 38 | .blob() 39 | .then(async data => { 40 | const isInList = funcaptchaListeningList.some(url => _url.indexOf(url) !== -1); 41 | if (isInList) { 42 | window.postMessage( 43 | { 44 | type: 'fetch', 45 | data: await data.text(), 46 | url: _url, 47 | }, 48 | '*', 49 | ); 50 | } 51 | }) 52 | .catch(err => { 53 | console.log(err); 54 | }); 55 | 56 | return response; 57 | }; 58 | })(); 59 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/inject/inject-hcaptcha.js: -------------------------------------------------------------------------------- 1 | const hcaptchaListeningList = [ 2 | 'hcaptcha.com/getcaptcha', 3 | ]; 4 | 5 | (function (xhr) { 6 | var XHR = XMLHttpRequest.prototype; 7 | 8 | var open = XHR.open; 9 | var send = XHR.send; 10 | 11 | XHR.open = function (method, url) { 12 | this._method = method; 13 | this._url = url; 14 | return open.apply(this, arguments); 15 | }; 16 | 17 | XHR.send = function (postData) { 18 | const _url = this._url; 19 | this.addEventListener('load', function () { 20 | const isInList = hcaptchaListeningList.some(url => _url.indexOf(url) !== -1); 21 | if (isInList) { 22 | window.postMessage({ type: 'xhr', data: this.response, url: _url }, '*'); 23 | } 24 | }); 25 | 26 | return send.apply(this, arguments); 27 | }; 28 | })(XMLHttpRequest); 29 | 30 | (function () { 31 | let origFetch = window.fetch; 32 | window.fetch = async function (...args) { 33 | const _url = args[0]; 34 | const response = await origFetch(...args); 35 | 36 | response 37 | .clone() 38 | .blob() 39 | .then(async data => { 40 | const isInList = hcaptchaListeningList.some(url => _url.indexOf(url) !== -1); 41 | if (isInList) { 42 | window.postMessage( 43 | { 44 | type: 'fetch', 45 | data: await data.text(), 46 | url: _url, 47 | }, 48 | '*', 49 | ); 50 | } 51 | }) 52 | .catch(err => { 53 | console.log(err); 54 | }); 55 | 56 | return response; 57 | }; 58 | })(); 59 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/inject/inject-recaptcha.js: -------------------------------------------------------------------------------- 1 | const recaptchaListeningList = [ 2 | '/recaptcha/api2/reload', 3 | '/recaptcha/api2/userverify', 4 | '/recaptcha/enterprise/reload', 5 | '/recaptcha/enterprise/userverify' 6 | ]; 7 | 8 | (function (xhr) { 9 | var XHR = XMLHttpRequest.prototype; 10 | 11 | var open = XHR.open; 12 | var send = XHR.send; 13 | 14 | XHR.open = function (method, url) { 15 | this._method = method; 16 | this._url = url; 17 | return open.apply(this, arguments); 18 | }; 19 | 20 | XHR.send = function (postData) { 21 | const _url = this._url; 22 | this.addEventListener('load', function () { 23 | const isInList = recaptchaListeningList.some(url => _url.indexOf(url) !== -1); 24 | if (isInList) { 25 | window.postMessage({ type: 'xhr', data: this.response, url: _url }, '*'); 26 | } 27 | }); 28 | 29 | return send.apply(this, arguments); 30 | }; 31 | })(XMLHttpRequest); 32 | 33 | (function () { 34 | let origFetch = window.fetch; 35 | window.fetch = async function (...args) { 36 | const _url = args[0]; 37 | const response = await origFetch(...args); 38 | 39 | response 40 | .clone() 41 | .blob() 42 | .then(async data => { 43 | const isInList = recaptchaListeningList.some(url => _url.indexOf(url) !== -1); 44 | if (isInList) { 45 | window.postMessage( 46 | { 47 | type: 'fetch', 48 | data: await data.text(), 49 | url: _url, 50 | }, 51 | '*', 52 | ); 53 | } 54 | }) 55 | .catch(err => { 56 | console.log(err); 57 | }); 58 | 59 | return response; 60 | }; 61 | })(); 62 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/inject/injected.js: -------------------------------------------------------------------------------- 1 | const capsolverListeningList = [ 2 | '/recaptcha/api2/reload', 3 | '/recaptcha/api2/userverify', 4 | '/recaptcha/enterprise/reload', 5 | '/recaptcha/enterprise/userverify', 6 | 'hcaptcha.com/getcaptcha', 7 | '/gfct', 8 | '/problem', 9 | '/verify', 10 | ]; 11 | 12 | (function (xhr) { 13 | var XHR = XMLHttpRequest.prototype; 14 | 15 | var open = XHR.open; 16 | var send = XHR.send; 17 | 18 | XHR.open = function (method, url) { 19 | this._method = method; 20 | this._url = url; 21 | return open.apply(this, arguments); 22 | }; 23 | 24 | XHR.send = function (postData) { 25 | const _url = this._url; 26 | this.addEventListener('load', function () { 27 | const isInList = capsolverListeningList.some(url => _url.indexOf(url) !== -1); 28 | if (isInList) { 29 | window.postMessage({ type: 'xhr', data: this.response, url: _url }, '*'); 30 | } 31 | }); 32 | 33 | return send.apply(this, arguments); 34 | }; 35 | })(XMLHttpRequest); 36 | 37 | (function () { 38 | let origFetch = window.fetch; 39 | window.fetch = async function (...args) { 40 | const _url = args[0]; 41 | const response = await origFetch(...args); 42 | 43 | response 44 | .clone() 45 | .blob() 46 | .then(async data => { 47 | const isInList = capsolverListeningList.some(url => _url.indexOf(url) !== -1); 48 | if (isInList) { 49 | window.postMessage( 50 | { 51 | type: 'fetch', 52 | data: await data.text(), 53 | url: _url, 54 | }, 55 | '*', 56 | ); 57 | } 58 | }) 59 | .catch(err => { 60 | console.log(err); 61 | }); 62 | 63 | return response; 64 | }; 65 | })(); 66 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/assets/inject/solvedCallback.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | window.addEventListener('message', function(event) { 3 | if (event.data.type !== 'capsolverCallback') return; 4 | window[event.data.callback]&& window[event.data.callback](); 5 | }) 6 | })(); -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/icons/icon-128x128.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/icons/icon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/icons/icon-16x16.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/icons/icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/icons/icon-48x48.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "update_url": "https://clients2.google.com/service/update2/crx", 3 | 4 | "manifest_version": 3, 5 | "default_locale": "en", 6 | "icons": { 7 | "16": "icons/icon-16x16.png", 8 | "48": "icons/icon-48x48.png", 9 | "128": "icons/icon-128x128.png" 10 | }, 11 | "version": "1.12.0", 12 | "permissions": [ 13 | "storage", 14 | "contextMenus" 15 | ], 16 | "host_permissions": [ 17 | "*://*/*" 18 | ], 19 | "action": { 20 | "default_icon": "icons/icon-48x48.png", 21 | "default_popup": "www/index.html#/popup", 22 | "default_title": "Captcha Solver: Auto captcha solving service" 23 | }, 24 | "devtools_page": "www/index.html#/devtools", 25 | "background": { 26 | "service_worker": "background.js" 27 | }, 28 | "content_scripts": [ 29 | { 30 | "all_frames": true, 31 | "run_at": "document_start", 32 | "matches": [ 33 | "http://*/*", 34 | "https://*/*" 35 | ], 36 | "css": [ 37 | "assets/content.css" 38 | ], 39 | "js": [ 40 | "my-content-script.js", 41 | "image-to-text.js" 42 | ] 43 | }, 44 | { 45 | "matches": [ 46 | "*://*.arkoselabs.com/fc/*", 47 | "*://*.funcaptcha.com/fc/*", 48 | "*://*.openai.com/fc/*" 49 | ], 50 | "js": [ 51 | "funcaptcha-recognition.js" 52 | ], 53 | "run_at": "document_end", 54 | "all_frames": true, 55 | "match_about_blank": true 56 | }, 57 | { 58 | "matches": [ 59 | "*://*.hcaptcha.com/captcha/*" 60 | ], 61 | "js": [ 62 | "hcaptcha-recognition.js" 63 | ], 64 | "run_at": "document_end", 65 | "all_frames": true, 66 | "match_about_blank": true 67 | }, 68 | { 69 | "matches": [ 70 | "*://*.google.com/recaptcha/*", 71 | "*://*.recaptcha.net/recaptcha/*", 72 | "*://recaptcha.net/recaptcha/*" 73 | ], 74 | "js": [ 75 | "recaptcha-recognition.js" 76 | ], 77 | "run_at": "document_end", 78 | "all_frames": true, 79 | "match_about_blank": true 80 | }, 81 | { 82 | "matches": [ 83 | "http://*/*", 84 | "https://*/*" 85 | ], 86 | "js": [ 87 | "aws-recognition.js" 88 | ], 89 | "run_at": "document_end", 90 | "all_frames": true, 91 | "match_about_blank": true 92 | } 93 | ], 94 | "content_security_policy": { 95 | "extension_pages": "script-src 'self'; object-src 'self';" 96 | }, 97 | "web_accessible_resources": [ 98 | { 99 | "resources": [ 100 | "*" 101 | ], 102 | "matches": [ 103 | "" 104 | ] 105 | } 106 | ], 107 | "name": "Captcha Solver: Auto captcha solving service", 108 | "short_name": "Captcha Solver: Auto captcha solving service", 109 | "description": "Automatically solve reCAPTCHA, hCaptcha, FunCaptcha, AWS WAF, and more types on any webpage." 110 | } -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/ErrorNotFound.d890cd68.js: -------------------------------------------------------------------------------- 1 | import{_ as e,o as t,c as s,a as l,b as a,Q as o}from"./index.2a9cb723.js";const c={},n={class:"fullscreen bg-blue text-white text-center q-pa-md flex flex-center"},r=l("div",{style:{"font-size":"30vh"}},"404",-1),i=l("div",{class:"text-h2",style:{opacity:"0.4"}},"Oops. Nothing here...",-1);var d=e(c,[["render",function(e,c){return t(),s("div",n,[l("div",null,[r,i,a(o,{class:"q-mt-xl",color:"white","text-color":"blue",unelevated:"",to:"/",label:"Go Home","no-caps":""})])])}]]);export{d as default}; 2 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOkCnqEu92Fr1MmgVxIIzQ.34e9582c.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOkCnqEu92Fr1MmgVxIIzQ.34e9582c.woff -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmEU9fBBc-.9ce7f3ac.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmEU9fBBc-.9ce7f3ac.woff -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmSU5fBBc-.bf14c7d7.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmSU5fBBc-.bf14c7d7.woff -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmWUlfBBc-.e0fd57c0.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmWUlfBBc-.e0fd57c0.woff -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmYUtfBBc-.f6537e32.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOlCnqEu92Fr1MmYUtfBBc-.f6537e32.woff -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOmCnqEu92Fr1Mu4mxM.f2abf7fb.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/KFOmCnqEu92Fr1Mu4mxM.f2abf7fb.woff -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Black.9f39397b.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Black.9f39397b.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-BlackItalic.fc73cdef.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-BlackItalic.fc73cdef.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Bold.d83ab9cc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Bold.d83ab9cc.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-BoldItalic.f401d78d.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-BoldItalic.f401d78d.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraBold.b98326c2.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraBold.b98326c2.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraBoldItalic.4ed4ee3c.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraBoldItalic.4ed4ee3c.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraLight.f5b6d5dd.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraLight.f5b6d5dd.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraLightItalic.70eb32b6.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ExtraLightItalic.70eb32b6.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Italic.e4f71a95.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Italic.e4f71a95.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Light.fb1ca566.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Light.fb1ca566.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-LightItalic.bda4ebaf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-LightItalic.bda4ebaf.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Medium.9b9b4a38.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Medium.9b9b4a38.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-MediumItalic.7d831f05.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-MediumItalic.7d831f05.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Regular.efb99a75.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Regular.efb99a75.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-SemiBold.f5bbc891.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-SemiBold.f5bbc891.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-SemiBoldItalic.631bd3f6.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-SemiBoldItalic.631bd3f6.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Thin.7c230e71.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-Thin.7c230e71.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ThinItalic.a1a633c9.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Poppins-ThinItalic.a1a633c9.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/Union.e4f5e32d.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/arrow.1ab57550.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/aws.08ef8f27.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/balance.ec909fe5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/cloudflare.a164bb78.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/copy.b3d46815.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/dataDome.047813e4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/en-US.553867d3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.fd84f88b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.fd84f88b.woff -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.83be7b2f.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.83be7b2f.woff2 -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/geetest.5dfc422c.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/key.201fc3f4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/lock.8b188c3a.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/logo-text.10d5eeb5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/logo-text.10d5eeb5.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/logo.eb4b912e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/logo.eb4b912e.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/question.6085c9ed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/ru.6c62f886.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/settings.8bf367a7.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/success.42815aad.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/textToImage.8dbe0bf9.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/tips.e99d9ebe.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/assets/zh-CN.c1f22841.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/favicon.ico -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/index.html: -------------------------------------------------------------------------------- 1 | Captcha Solver: Auto captcha solving service 2 | 3 |
-------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver-chrome-extension/www/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver-chrome-extension/www/logo.png -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver_captcha_solver-1.10.4.crx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver_captcha_solver-1.10.4.crx -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/capsolver_captcha_solver-1.10.4.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/capsolver_captcha_solver-1.10.4.xpi -------------------------------------------------------------------------------- /ninjemail/captcha_solvers/noptcha-0.4.9.xpi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/captcha_solvers/noptcha-0.4.9.xpi -------------------------------------------------------------------------------- /ninjemail/config.toml: -------------------------------------------------------------------------------- 1 | # config.toml 2 | CAPTCHA_SERVICES_SUPPORTED = ["capsolver", "nopecha"] 3 | DEFAULT_CAPTCHA_SERVICE = "capsolver" 4 | SMS_SERVICES_SUPPORTED = ["getsmscode", "smspool", "5sim"] 5 | DEFAULT_SMS_SERVICE = "smspool" 6 | SUPPORTED_BROWSERS = ['firefox', 'chrome', 'undetected-chrome'] 7 | 8 | [[SUPPORTED_SOLVERS_BY_EMAIL]] 9 | email_service = "outlook" 10 | solvers = ["capsolver", "nopecha"] 11 | 12 | [[SUPPORTED_SOLVERS_BY_EMAIL]] 13 | email_service = "yahoo" 14 | solvers = ["capsolver", "nopecha"] 15 | -------------------------------------------------------------------------------- /ninjemail/config/__init__.py: -------------------------------------------------------------------------------- 1 | import toml 2 | import os 3 | 4 | # Load configuration from the TOML file 5 | config_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'config.toml') 6 | config = toml.load(config_path) 7 | 8 | # Expose configuration variables as module-level variables 9 | CAPTCHA_SERVICES_SUPPORTED = config.get("CAPTCHA_SERVICES_SUPPORTED", []) 10 | DEFAULT_CAPTCHA_SERVICE = config.get("DEFAULT_CAPTCHA_SERVICE", "") 11 | SMS_SERVICES_SUPPORTED = config.get("SMS_SERVICES_SUPPORTED", []) 12 | DEFAULT_SMS_SERVICE = config.get("DEFAULT_SMS_SERVICE", "") 13 | SUPPORTED_BROWSERS = config.get("SUPPORTED_BROWSERS", []) 14 | 15 | SUPPORTED_SOLVERS_BY_EMAIL = {} 16 | for item in config['SUPPORTED_SOLVERS_BY_EMAIL']: 17 | email_service = item['email_service'] 18 | solvers = item['solvers'] 19 | SUPPORTED_SOLVERS_BY_EMAIL[email_service] = solvers 20 | -------------------------------------------------------------------------------- /ninjemail/email_providers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/email_providers/__init__.py -------------------------------------------------------------------------------- /ninjemail/email_providers/outlook.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Optional, Tuple 3 | from utils.web_helpers import wait_and_click, set_input_value 4 | from selenium.common.exceptions import TimeoutException 5 | from selenium.webdriver.common.by import By 6 | from selenium.webdriver.remote.webdriver import WebDriver 7 | from selenium.webdriver.support import expected_conditions as EC 8 | from selenium.webdriver.support.ui import WebDriverWait, Select 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | # Centralized selector configuration 13 | SELECTORS = { 14 | "email_switch": (By.ID, 'liveSwitch'), 15 | "username_input": (By.ID, 'usernameInput'), 16 | "domain_select": (By.ID, 'domainSelect'), 17 | "next_button": (By.ID, 'nextButton'), 18 | "show_password": (By.ID, 'ShowHidePasswordCheckbox'), 19 | "optin_email": (By.ID, 'iOptinEmail'), 20 | "password_input": (By.ID, 'Password'), 21 | "first_name_input": (By.ID, 'firstNameInput'), 22 | "last_name_input": (By.ID, 'lastNameInput'), 23 | "country_select": (By.ID, 'countryRegionDropdown'), 24 | "birth_month": (By.ID, 'BirthMonth'), 25 | "birth_day": (By.ID, 'BirthDay'), 26 | "birth_year": (By.ID, 'BirthYear'), 27 | "captcha_frame": (By.ID, "enforcementFrame"), 28 | "captcha_reload": (By.XPATH, "//button[contains(text(), 'Reload Challenge')]"), 29 | "success_message": (By.XPATH, "//span[contains(text(), 'A quick note about your Microsoft account')]"), 30 | "ok_button": (By.ID, "id__0") 31 | } 32 | 33 | WAIT_TIMEOUT = 10 34 | MAX_CAPTCHA_RETRIES = 3 35 | CAPTCHA_RETRY_DELAY = 60 36 | 37 | class AccountCreationError(Exception): 38 | """Base exception for account creation failures""" 39 | pass 40 | 41 | def select_dropdown(driver: WebDriver, by: Tuple[str, str], value: str) -> None: 42 | """Select an option from a dropdown menu""" 43 | element = WebDriverWait(driver, WAIT_TIMEOUT).until( 44 | EC.presence_of_element_located(by) 45 | ) 46 | Select(element).select_by_visible_text(value) 47 | 48 | def select_dropdown_by_index(driver: WebDriver, by: Tuple[str, str], index: int) -> None: 49 | """Select a dropdown option by index""" 50 | element = WebDriverWait(driver, WAIT_TIMEOUT).until( 51 | EC.presence_of_element_located(by) 52 | ) 53 | Select(element).select_by_index(index) 54 | 55 | def handle_captcha(driver: WebDriver) -> None: 56 | """Handle Microsoft account captcha challenge""" 57 | success = False 58 | try: 59 | # Switch to captcha frames 60 | WebDriverWait(driver, WAIT_TIMEOUT).until( 61 | EC.frame_to_be_available_and_switch_to_it(SELECTORS["captcha_frame"]) 62 | ) 63 | WebDriverWait(driver, WAIT_TIMEOUT).until( 64 | EC.frame_to_be_available_and_switch_to_it((By.TAG_NAME, "iframe")) 65 | ) 66 | WebDriverWait(driver, WAIT_TIMEOUT).until( 67 | EC.frame_to_be_available_and_switch_to_it((By.ID, "game-core-frame")) 68 | ) 69 | 70 | # Initial captcha click 71 | wait_and_click(driver, (By.CSS_SELECTOR, "div#root > div > div > button")) 72 | 73 | # Handle potential retries 74 | for _ in range(MAX_CAPTCHA_RETRIES): 75 | try: 76 | WebDriverWait(driver, CAPTCHA_RETRY_DELAY).until( 77 | EC.url_contains('privacynotice') 78 | ) 79 | if 'privacynotice' in driver.current_url: 80 | success = True 81 | break 82 | except TimeoutException: 83 | continue 84 | if not success: 85 | raise AccountCreationError("The captcha was not solved") 86 | except Exception as e: 87 | logger.error("Captcha handling failed: %s", str(e)) 88 | raise AccountCreationError("Captcha challenge failed") from e 89 | finally: 90 | driver.switch_to.default_content() 91 | 92 | def verify_account_creation(driver: WebDriver) -> bool: 93 | """Verify successful account creation and complete final steps""" 94 | try: 95 | WebDriverWait(driver, WAIT_TIMEOUT).until( 96 | EC.visibility_of_element_located(SELECTORS["success_message"]) 97 | ) 98 | 99 | # Complete post-creation steps 100 | wait_and_click(driver, SELECTORS["ok_button"]) 101 | 102 | return True 103 | except TimeoutException: 104 | logger.error("Account creation verification timeout") 105 | return False 106 | 107 | def create_account( 108 | driver: WebDriver, 109 | username: str, 110 | password: str, 111 | first_name: str, 112 | last_name: str, 113 | country: str, 114 | month: str, 115 | day: str, 116 | year: str, 117 | hotmail: bool 118 | ) -> Tuple[Optional[str], Optional[str]]: 119 | """ 120 | Create a new Microsoft account (Outlook/Hotmail) with enhanced reliability 121 | 122 | Returns: 123 | Tuple: (email, password) or (None, None) on failure 124 | """ 125 | try: 126 | logger.info('Starting Microsoft account creation process') 127 | driver.get('https://signup.live.com/signup') 128 | 129 | # Initial email setup 130 | wait_and_click(driver, SELECTORS["email_switch"]) 131 | driver.implicitly_wait(2) 132 | set_input_value(driver, SELECTORS["username_input"], username) 133 | 134 | if hotmail: 135 | select_dropdown_by_index(driver, SELECTORS["domain_select"], 1) 136 | 137 | wait_and_click(driver, SELECTORS["next_button"]) 138 | 139 | # Password setup 140 | try: 141 | wait_and_click(driver, SELECTORS["show_password"]) 142 | wait_and_click(driver, SELECTORS["optin_email"]) 143 | except TimeoutException: 144 | logger.debug("Optional password visibility elements not found") 145 | 146 | set_input_value(driver, SELECTORS["password_input"], password) 147 | wait_and_click(driver, SELECTORS["next_button"]) 148 | 149 | # Personal information 150 | set_input_value(driver, SELECTORS["first_name_input"], first_name) 151 | set_input_value(driver, SELECTORS["last_name_input"], last_name) 152 | wait_and_click(driver, SELECTORS["next_button"]) 153 | 154 | # Demographic information 155 | select_dropdown(driver, SELECTORS["country_select"], country) 156 | select_dropdown_by_index(driver, SELECTORS["birth_month"], int(month)) 157 | select_dropdown_by_index(driver, SELECTORS["birth_day"], int(day)) 158 | set_input_value(driver, SELECTORS["birth_year"], year) 159 | wait_and_click(driver, SELECTORS["next_button"]) 160 | 161 | # Captcha handling 162 | handle_captcha(driver) 163 | 164 | # Final verification 165 | if not verify_account_creation(driver): 166 | raise AccountCreationError("Account creation verification failed") 167 | 168 | # Log successful creation 169 | logger.info(f"{"Hotmail" if hotmail else "Outlook"} account created successfully") 170 | logger.debug("Account details: %s@%s.com", username, "hotmail" if hotmail else "outlook") 171 | 172 | return f"{username}@{'hotmail' if hotmail else 'outlook'}.com", password 173 | 174 | except Exception as e: 175 | logger.error("Account creation failed: %s", str(e)) 176 | raise AccountCreationError("Microsoft account creation process failed") from e 177 | finally: 178 | driver.quit() 179 | -------------------------------------------------------------------------------- /ninjemail/email_providers/yahoo.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import Optional, Tuple 3 | from selenium.common.exceptions import TimeoutException, NoSuchElementException 4 | from selenium.webdriver.common.by import By 5 | from selenium.webdriver.common.keys import Keys 6 | from selenium.webdriver.remote.webdriver import WebDriver 7 | from selenium.webdriver.support import expected_conditions as EC 8 | from selenium.webdriver.support.ui import WebDriverWait, Select 9 | from sms_services import get_sms_instance 10 | from utils.web_helpers import safe_click, wait_and_click, set_input_value 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | # Constants 15 | URL = 'https://login.yahoo.com/account/create' 16 | WAIT_TIMEOUT = 25 17 | MAX_CAPTCHA_RETRIES = 3 18 | CAPTCHA_SOLVE_TIMEOUT = 120 19 | 20 | # Centralized selector configuration 21 | SELECTORS = { 22 | "username": (By.ID, 'usernamereg-userId'), 23 | "password": (By.ID, 'usernamereg-password'), 24 | "first_name": (By.ID, 'usernamereg-firstName'), 25 | "last_name": (By.ID, 'usernamereg-lastName'), 26 | "birth_month": (By.ID, 'usernamereg-month'), 27 | "birth_day": (By.ID, 'usernamereg-day'), 28 | "birth_year": (By.ID, 'usernamereg-year'), 29 | "submit_button": (By.ID, 'reg-submit-button'), 30 | "phone_input": (By.ID, 'usernamereg-phone'), 31 | "recaptcha_frame": (By.ID, "recaptcha-iframe"), 32 | "funcaptcha_frame": (By.ID, "arkose-iframe"), 33 | "verification_code": (By.ID, "verification-code-field"), 34 | "success_page": (By.XPATH, "//h1[contains(., 'Account created')]") 35 | } 36 | 37 | class AccountCreationError(Exception): 38 | """Base exception for Yahoo account creation failures""" 39 | pass 40 | 41 | def handle_captcha(driver: WebDriver) -> None: 42 | """Handle Yahoo's captcha challenges with retries""" 43 | try: 44 | # Try reCAPTCHA first 45 | WebDriverWait(driver, CAPTCHA_SOLVE_TIMEOUT).until( 46 | EC.frame_to_be_available_and_switch_to_it(SELECTORS["recaptcha_frame"]) 47 | ) 48 | try: 49 | complete_btn = WebDriverWait(driver, CAPTCHA_SOLVE_TIMEOUT).until( 50 | EC.element_to_be_clickable((By.ID, "recaptcha-submit")) 51 | ) 52 | safe_click(complete_btn) 53 | finally: 54 | driver.switch_to.default_content() 55 | 56 | except TimeoutException: 57 | # Fallback to FunCaptcha 58 | try: 59 | WebDriverWait(driver, WAIT_TIMEOUT).until( 60 | EC.frame_to_be_available_and_switch_to_it(SELECTORS["funcaptcha_frame"]) 61 | ) 62 | WebDriverWait(driver, CAPTCHA_SOLVE_TIMEOUT).until( 63 | EC.visibility_of_element_located((By.XPATH, "//h2[contains(., 'Security check complete')]")) 64 | ) 65 | safe_click(driver.find_element(By.ID, 'arkose-submit')) 66 | finally: 67 | driver.switch_to.default_content() 68 | 69 | def handle_phone_submission(driver: WebDriver, sms_key, sms_provider) -> dict: 70 | """Handle phone verification process""" 71 | phone_info = {} 72 | next_button_selectors = [ 73 | (By.ID, 'reg-sms-button'), 74 | (By.ID, 'reg-submit-button') 75 | ] 76 | try: 77 | if sms_key['name'] == 'getsmscode': 78 | phone = sms_provider.get_phone(send_prefix=False) 79 | phone_info.update({'phone': phone}) 80 | elif sms_key['name'] in ['smspool', '5sim']: 81 | phone, order_id = sms_provider.get_phone(send_prefix=False) 82 | phone_info.update({'phone': phone, 'order_id': order_id}) 83 | 84 | set_input_value(driver, SELECTORS["phone_input"], str(phone_info.get('phone'))) 85 | 86 | for selector in next_button_selectors: 87 | try: 88 | wait_and_click(driver, selector, timeout=10) 89 | return phone_info 90 | except (TimeoutException, NoSuchElementException): 91 | continue 92 | 93 | raise TimeoutException("No valid next button found after phone entry") 94 | except Exception as e: 95 | logger.error("Phone submission failed: %s", str(e)) 96 | raise AccountCreationError("Phone verification step failed") from e 97 | 98 | def verify_phone(driver: WebDriver, sms_key, sms_provider, phone_info: dict) -> None: 99 | """Handle SMS verification process""" 100 | try: 101 | if sms_key['name'] == 'getsmscode': 102 | code = sms_provider.get_code(phone_info['phone']) 103 | elif sms_key['name'] in ['smspool', '5sim']: 104 | code = sms_provider.get_code(phone_info['order_id']) 105 | code_input = WebDriverWait(driver, WAIT_TIMEOUT).until( 106 | EC.element_to_be_clickable(SELECTORS["verification_code"]) 107 | ) 108 | code_input.send_keys(str(code) + Keys.ENTER) 109 | except Exception as e: 110 | logger.error("SMS verification failed: %s", str(e)) 111 | raise AccountCreationError("Phone verification failed") from e 112 | 113 | def create_account( 114 | driver: WebDriver, 115 | sms_key: dict, 116 | username: str, 117 | password: str, 118 | first_name: str, 119 | last_name: str, 120 | month: str, 121 | day: str, 122 | year: str, 123 | ) -> Tuple[Optional[str], Optional[str]]: 124 | """ 125 | Create a new Yahoo account with improved reliability 126 | 127 | Returns: 128 | Tuple: (email, password) or (None, None) on failure 129 | """ 130 | try: 131 | logger.info('Starting Yahoo account creation process') 132 | driver.get(URL) 133 | 134 | # Account basics 135 | set_input_value(driver, SELECTORS["username"], username) 136 | set_input_value(driver, SELECTORS["password"], password) 137 | set_input_value(driver, SELECTORS["first_name"], first_name) 138 | set_input_value(driver, SELECTORS["last_name"], last_name) 139 | 140 | # Birthdate 141 | Select(WebDriverWait(driver, WAIT_TIMEOUT).until( 142 | EC.presence_of_element_located(SELECTORS["birth_month"]) 143 | )).select_by_index(int(month)) 144 | 145 | set_input_value(driver, SELECTORS["birth_day"], day) 146 | set_input_value(driver, SELECTORS["birth_year"], year) 147 | 148 | wait_and_click(driver, SELECTORS["submit_button"]) 149 | 150 | # Phone verification 151 | sms_provider = get_sms_instance(sms_key, 'yahoo') 152 | phone_info = handle_phone_submission(driver, sms_key, sms_provider) 153 | 154 | # Captcha handling 155 | if not 'phone-verify' in driver.current_url: 156 | handle_captcha(driver) 157 | 158 | # SMS verification 159 | verify_phone(driver, sms_key, sms_provider, phone_info) 160 | 161 | # Verify success state 162 | WebDriverWait(driver, WAIT_TIMEOUT).until( 163 | EC.any_of( 164 | EC.url_contains("create/success"), 165 | EC.url_contains("account/upsell/webauth") 166 | ) 167 | ) 168 | 169 | # Log successful creation 170 | logger.info("Yahoo account created successfully") 171 | logger.debug("Account details: %s@yahoo.com", username) 172 | 173 | return f"{username}@yahoo.com", password 174 | 175 | except Exception as e: 176 | logger.error("Account creation failed: %s", str(e)) 177 | raise AccountCreationError("Yahoo account creation failed") from e 178 | finally: 179 | driver.quit() 180 | 181 | -------------------------------------------------------------------------------- /ninjemail/sms_services/__init__.py: -------------------------------------------------------------------------------- 1 | from sms_services import getsmscode 2 | from sms_services import smspool 3 | from sms_services import fivesim 4 | 5 | def get_sms_instance(sms_info, email_provider): 6 | """ 7 | Retrieves an instance of an SMS provider based on the given SMS information. 8 | 9 | Args: 10 | sms_info (dict): A dictionary containing the SMS service name and associated data. 11 | 12 | Returns: 13 | object: An instance of the SMS provider based on the provided SMS service. 14 | """ 15 | service_name = sms_info['name'] 16 | 17 | if service_name == 'getsmscode': 18 | data = sms_info['data'] 19 | project = 1 20 | if email_provider == 'yahoo': 21 | project = 15 22 | data.update({'project': project, 'country': 'us'}) 23 | sms_provider = getsmscode.GetsmsCode(**data) 24 | elif service_name == 'smspool': 25 | data = sms_info['data'] 26 | service = 395 27 | if email_provider == 'yahoo': 28 | service = 1034 29 | data.update({'service': service}) 30 | sms_provider = smspool.SMSPool(**data) 31 | elif service_name == '5sim': 32 | data = sms_info['data'] 33 | data.update({'service': email_provider}) 34 | sms_provider = fivesim.FiveSim(**data) 35 | 36 | return sms_provider 37 | -------------------------------------------------------------------------------- /ninjemail/sms_services/fivesim.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import re 3 | import time 4 | 5 | import requests 6 | 7 | PREFIXES = { 8 | "usa":"1", 9 | } 10 | 11 | class APIError(Exception): 12 | pass 13 | 14 | class FiveSim: 15 | """ 16 | This class provides functionalities to interact with the 5Sim API to obtain phone numbers and SMS verification codes. 17 | 18 | Attributes: 19 | token (str): Your 5Sim api key. 20 | service (str): 5Sim service name. 21 | country (str, optional): The country name for the phone number. Defaults to 'usa'. 22 | 23 | Methods: 24 | request(kwargs): Sends a GET request to the 5Sim API with the provided arguments. 25 | get_phone(send_prefix=False): Purchases a phone number from the 5Sim API. 26 | - send_prefix (bool, optional): Specifies whether to return the phone number with or without the prefix. Defaults to False. 27 | get_code(phone): Retrieves the SMS verification code sent to the provided phone number. 28 | 29 | Exceptions: 30 | APIError: Raised when an error occurs while interacting with the 5Sim API. 31 | """ 32 | 33 | _last_phone = None 34 | code_patt = re.compile(r"([0-9]{5,6})") 35 | 36 | def __init__( 37 | self, 38 | service, 39 | token, 40 | country='usa', 41 | ): 42 | self.token = token 43 | self.service = service 44 | self.country = country 45 | self.prefix = PREFIXES.get(self.country) or '' 46 | self.API_URL = "https://5sim.net/v1/user/" 47 | 48 | def request(self, cmd): 49 | """ 50 | Sends a GET request to the 5Sim API with the provided arguments. 51 | 52 | Args: 53 | kwargs (dict): Additional arguments to be included in the request body. 54 | 55 | Returns: 56 | str: The API response text. 57 | 58 | Raises: 59 | APIError: If the API returns an error message. 60 | """ 61 | headers = { 62 | 'Authorization': 'Bearer ' + self.token, 63 | } 64 | 65 | res = requests.get( 66 | self.API_URL + cmd, 67 | headers=headers, 68 | ) 69 | try: 70 | res.raise_for_status() 71 | except requests.exceptions.HTTPError as err: 72 | raise APIError(str(err)) 73 | 74 | if res.text == "no free phones": 75 | raise APIError('5Sim has no free phones') 76 | if res.text == "not enough user balance": 77 | raise APIError("Not enough balance") 78 | 79 | return res.json() 80 | 81 | def get_phone(self, send_prefix=False): 82 | """ 83 | Purchases a phone number from the 5Sim API. 84 | 85 | Args: 86 | send_prefix (bool, optional): Specifies whether to return the phone number with or without the prefix. Defaults to False. 87 | 88 | Returns: 89 | str: The retrieved phone number, optionally with the prefix removed and the order id of the purchased phone number. 90 | 91 | Raises: 92 | APIError: If an error occurs while retrieving the phone number. 93 | """ 94 | logging.info("Getting a phone number") 95 | 96 | cmd = 'buy/activation/' + self.country + '/any/' + self.service 97 | data = self.request(cmd=cmd) 98 | 99 | self._last_phone = data 100 | phone_number = data['phone'] 101 | phone_number = phone_number.removeprefix('+') 102 | order_id = data['id'] 103 | 104 | logging.info("Got phone: %s", phone_number) 105 | 106 | if not send_prefix: 107 | phone_number = phone_number.removeprefix('1') 108 | return phone_number, order_id 109 | 110 | def get_code(self, order_id): 111 | """ 112 | Retrieves the SMS verification code sent to the provided phone number. 113 | 114 | Args: 115 | order_id (str): The order_id to retrieve the code for the sms. 116 | 117 | Returns: 118 | str: The extracted SMS verification code. 119 | 120 | Raises: 121 | APIError: If an error occurs while retrieving the code. 122 | AssertionError: If no code is found in the API response. 123 | """ 124 | logging.info("Getting the verification code") 125 | 126 | cmd = '/check/' + str(order_id) 127 | received = False 128 | while not received: 129 | res = self.request(cmd=cmd) 130 | if res['sms']: 131 | received = True 132 | elif res['status'] in ['CANCELED', 'TIMEOUT', 'BANNED']: 133 | raise APIError('Error getting verification code, order status: %s' % res['status']) 134 | else: 135 | logging.info("Retrying...") 136 | time.sleep(10) 137 | 138 | sms = res['sms'] 139 | code = sms[0]['code'] 140 | 141 | logging.info("Got code %s", code) 142 | return code 143 | 144 | 145 | -------------------------------------------------------------------------------- /ninjemail/sms_services/getsmscode.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import random 3 | import re 4 | import time 5 | 6 | import requests 7 | 8 | PREFIXES = { 9 | "us":"1", 10 | "hk": "852", 11 | } 12 | 13 | class APIError(Exception): 14 | pass 15 | 16 | class GetsmsCode: 17 | """ 18 | This class provides functionalities to interact with the GetsmsCode API to obtain phone numbers and SMS verification codes. 19 | 20 | Attributes: 21 | user (str): Your GetsmsCode username. 22 | token (str): Your GetsmsCode token. 23 | project (str): GetsmsCode project ID. 24 | country (str, optional): The country code for the phone number. Defaults to 'hk'. 25 | prefix (str): The phone number prefix for the specified country. 26 | API_URL (str): The base URL for the GetsmsCode API. 27 | 28 | Methods: 29 | _generate_generic(): Generates a random 7-digit phone number. 30 | get_endpoint(ccode): Returns the appropriate GetsmsCode API endpoint based on the provided country code. 31 | request(kwargs): Sends a POST request to the GetsmsCode API with the provided arguments. 32 | get_phone(send_prefix=False): Retrieves a phone number from the GetsmsCode API. 33 | - send_prefix (bool, optional): Specifies whether to return the phone number with or without the prefix. Defaults to False. 34 | get_code(phone): Retrieves the SMS verification code sent to the provided phone number. 35 | 36 | Exceptions: 37 | APIError: Raised when an error occurs while interacting with the GetsmsCode API. 38 | """ 39 | 40 | _last_phone = None 41 | code_patt = re.compile(r"([0-9]{5,6})") 42 | 43 | def __init__( 44 | self, 45 | project, 46 | user, 47 | token, 48 | country="hk", 49 | ): 50 | self.user = user 51 | self.token = token 52 | self.project = project 53 | self.country = country 54 | self.prefix = PREFIXES.get(self.country) or '' 55 | self.API_URL = f"http://api.getsmscode.com/{self.get_endpoint(country)}.php" 56 | 57 | def _generate_generic(self): 58 | """ 59 | Generates a random 7-digit phone number starting with "52". 60 | 61 | Returns: 62 | str: The generated phone number. 63 | """ 64 | return "52" + str(random.randint(234562, 777777)) 65 | 66 | def get_endpoint(self, ccode): 67 | """ 68 | Returns the appropriate GetsmsCode API endpoint based on the provided country code. 69 | 70 | Args: 71 | ccode (str): The country code for the phone number. 72 | 73 | Returns: 74 | str: The corresponding GetsmsCode API endpoint. 75 | """ 76 | if ccode in { 77 | "hk", 78 | }: 79 | return "vndo" 80 | if ccode in { 81 | "us", 82 | }: 83 | return "usdo" 84 | return "do" 85 | 86 | def request(self, **kwargs): 87 | """ 88 | Sends a POST request to the GetsmsCode API with the provided arguments. 89 | 90 | Args: 91 | kwargs (dict): Additional arguments to be included in the request body. 92 | 93 | Returns: 94 | str: The API response text. 95 | 96 | Raises: 97 | APIError: If the API returns an error message. 98 | """ 99 | if self.country not in {"us", "cn"}: 100 | kwargs["cocode"] = self.country 101 | 102 | res = requests.post( 103 | self.API_URL, 104 | data=dict( 105 | username=self.user, 106 | token=self.token, 107 | pid=self.project, 108 | **kwargs, 109 | ) 110 | ) 111 | res.raise_for_status() 112 | 113 | text = res.text 114 | if "Message" in text: 115 | raise APIError(text) 116 | 117 | return text 118 | 119 | def get_phone(self, send_prefix=False): 120 | """ 121 | Retrieves a phone number from the GetsmsCode API. 122 | 123 | Args: 124 | send_prefix (bool, optional): Specifies whether to return the phone number with or without the prefix. Defaults to False. 125 | 126 | Returns: 127 | str: The retrieved phone number, optionally with the prefix removed. 128 | 129 | Raises: 130 | APIError: If an error occurs while retrieving the phone number. 131 | """ 132 | logging.info("Getting a phone number") 133 | 134 | data = { 135 | "action": "getmobile", 136 | } 137 | 138 | data = self.request(**data) 139 | 140 | self._last_phone = data 141 | logging.info("Got phone: %s", data) 142 | 143 | if not send_prefix: 144 | data = data.removeprefix(self.prefix) 145 | return data.strip() 146 | 147 | def get_code(self, phone): 148 | """ 149 | Retrieves the SMS verification code sent to the provided phone number. 150 | 151 | Args: 152 | phone (str): The phone number to retrieve the code for. 153 | 154 | Returns: 155 | str: The extracted SMS verification code. 156 | 157 | Raises: 158 | APIError: If an error occurs while retrieving the code. 159 | AssertionError: If no code is found in the API response. 160 | """ 161 | logging.info("Getting the code with phone %s", phone) 162 | 163 | data = { 164 | "action": "getsms", 165 | "mobile": phone, 166 | } 167 | while True: 168 | try: 169 | text = self.request(**data) 170 | except APIError as exc: 171 | logging.info("Retrying...") 172 | time.sleep(10) 173 | else: 174 | break 175 | match = re.search(self.code_patt, text.split("|")[1]) 176 | assert match, f"No code in {text}" 177 | 178 | logging.info("Got code %s", match.group()) 179 | return match.groups()[0] 180 | -------------------------------------------------------------------------------- /ninjemail/sms_services/smspool.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import random 3 | import re 4 | import time 5 | 6 | import requests 7 | 8 | class APIError(Exception): 9 | pass 10 | 11 | class SMSPool: 12 | """ 13 | This class provides functionalities to interact with the SMSPool API to obtain phone numbers and SMS verification codes. 14 | 15 | Attributes: 16 | token (str): Your SMSPool api key. 17 | service (str): SMSPool service ID. 18 | country (str, optional): The country code for the phone number. Defaults to 'hk'. 19 | 20 | Methods: 21 | request(kwargs): Sends a POST request to the SMSPool API with the provided arguments. 22 | get_phone(send_prefix=False): Purchases a phone number from the SMSPool API. 23 | - send_prefix (bool, optional): Specifies whether to return the phone number with or without the prefix. Defaults to False. 24 | get_code(phone): Retrieves the SMS verification code sent to the provided phone number. 25 | 26 | Exceptions: 27 | APIError: Raised when an error occurs while interacting with the SMSPool API. 28 | """ 29 | 30 | _last_phone = None 31 | code_patt = re.compile(r"([0-9]{5,6})") 32 | 33 | def __init__( 34 | self, 35 | service, 36 | token, 37 | country=1, 38 | ): 39 | self.token = token 40 | self.service = service 41 | self.country = country 42 | self.API_URL = "http://api.smspool.net/" 43 | 44 | def request(self, cmd, **kwargs): 45 | """ 46 | Sends a POST request to the SMSPool API with the provided arguments. 47 | 48 | Args: 49 | kwargs (dict): Additional arguments to be included in the request body. 50 | 51 | Returns: 52 | str: The API response text. 53 | 54 | Raises: 55 | APIError: If the API returns an error message. 56 | """ 57 | payload = dict( 58 | key=self.token, 59 | **kwargs 60 | ) 61 | 62 | res = requests.post( 63 | self.API_URL + cmd, 64 | params=payload 65 | ) 66 | res.raise_for_status() 67 | 68 | res = res.json() 69 | if 'success' in res: 70 | if not res['success']: 71 | raise APIError(res.get('message', 'Unknown error')) 72 | elif 'status' in res: 73 | if res['status'] != 3: 74 | raise APIError(res.get('message', 'Unknown error')) 75 | 76 | return res 77 | 78 | def get_phone(self, send_prefix=False): 79 | """ 80 | Purchases a phone number from the SMSPool API. 81 | 82 | Args: 83 | send_prefix (bool, optional): Specifies whether to return the phone number with or without the prefix. Defaults to False. 84 | 85 | Returns: 86 | str: The retrieved phone number, optionally with the prefix removed and the order id of the purchased phone number. 87 | 88 | Raises: 89 | APIError: If an error occurs while retrieving the phone number. 90 | """ 91 | logging.info("Getting a phone number") 92 | 93 | data = { 94 | "country": self.country, 95 | "service": self.service, 96 | "pricing_option": 0, 97 | } 98 | 99 | data = self.request(cmd="purchase/sms", **data) 100 | 101 | self._last_phone = data 102 | phone_number = data['number'] 103 | order_id = data['order_id'] 104 | 105 | logging.info("Got phone: %s", phone_number) 106 | 107 | if not send_prefix: 108 | phone_number = data['phonenumber'] 109 | return phone_number, order_id 110 | 111 | def get_code(self, order_id): 112 | """ 113 | Retrieves the SMS verification code sent to the provided phone number. 114 | 115 | Args: 116 | order_id (str): The order_id to retrieve the code for the sms. 117 | 118 | Returns: 119 | str: The extracted SMS verification code. 120 | 121 | Raises: 122 | APIError: If an error occurs while retrieving the code. 123 | AssertionError: If no code is found in the API response. 124 | """ 125 | logging.info("Getting the verification code") 126 | 127 | data = { 128 | "orderid": order_id, 129 | } 130 | while True: 131 | try: 132 | res = self.request(cmd="sms/check", **data) 133 | except APIError as exc: 134 | logging.info("Retrying...") 135 | time.sleep(10) 136 | else: 137 | break 138 | code = res['sms'] 139 | 140 | logging.info("Got code %s", code) 141 | return code 142 | 143 | -------------------------------------------------------------------------------- /ninjemail/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/david96182/ninjemail/f9d2173710502406e096bdc97573718b4bfc4d71/ninjemail/tests/__init__.py -------------------------------------------------------------------------------- /ninjemail/tests/test_email_gmail.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from unittest.mock import Mock, MagicMock 3 | from selenium.webdriver.common.keys import Keys 4 | from ..email_providers.gmail import create_account 5 | from ..utils.webdriver_utils import create_driver 6 | 7 | @pytest.fixture(autouse=True) 8 | def mock_gmail(monkeypatch): 9 | # Mock GeckoDriverManager and ChromeDriverManager installations 10 | monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', lambda *args, **kwargs: 'gecko_driver_path') 11 | monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', lambda *args, **kwargs: 'chrome_driver_path') 12 | 13 | # Mock WebDriver classes 14 | mock_firefox = Mock() 15 | mock_chrome = Mock() 16 | monkeypatch.setattr('selenium.webdriver.Firefox', lambda *args, **kwargs: mock_firefox) 17 | monkeypatch.setattr('selenium.webdriver.Chrome', lambda *args, **kwargs: mock_chrome) 18 | 19 | # Mock WebDriver methods 20 | mock_firefox.get = MagicMock() 21 | mock_chrome.get = MagicMock() 22 | mock_firefox.find_element = MagicMock(return_value=Mock()) 23 | mock_chrome.find_element = MagicMock(return_value=Mock()) 24 | mock_firefox.find_elements = MagicMock(return_value=[Mock()]) 25 | mock_chrome.find_elements = MagicMock(return_value=[Mock()]) 26 | mock_firefox.quit = MagicMock() 27 | mock_chrome.quit = MagicMock() 28 | 29 | # Mock WebDriverWait and expected_conditions 30 | mock_wait = MagicMock() 31 | monkeypatch.setattr('selenium.webdriver.support.ui.WebDriverWait', lambda *args, **kwargs: mock_wait) 32 | mock_wait.until = MagicMock(return_value=Mock()) 33 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.presence_of_element_located', lambda *args, **kwargs: MagicMock()) 34 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.element_to_be_clickable', lambda *args, **kwargs: MagicMock()) 35 | 36 | # Correctly mock Select class 37 | def mock_select_init(self, *args, **kwargs): 38 | self.select_by_index = MagicMock() 39 | self.select_by_visible_text = MagicMock() 40 | self.select_by_value = MagicMock() 41 | 42 | monkeypatch.setattr('selenium.webdriver.support.ui.Select.__init__', mock_select_init) 43 | 44 | # Mock Keys 45 | monkeypatch.setattr('selenium.webdriver.common.keys.Keys', Keys) 46 | 47 | # Mock time 48 | monkeypatch.setattr('time.sleep', MagicMock(())) 49 | 50 | # Mock logging 51 | monkeypatch.setattr('logging.info', MagicMock()) 52 | monkeypatch.setattr('logging.error', MagicMock()) 53 | 54 | # Mock sms services 55 | def mock_get_phone_getsmscode(self, *args, **kwargs): 56 | return '111111111' 57 | 58 | def mock_get_phone_smspool(self, *args, **kwargs): 59 | return 'ordeid', '111111111' 60 | 61 | def mock_get_phone_fivesim(self, *args, **kwargs): 62 | return 'ordeid', '111111111' 63 | 64 | def mock_get_code(self, *arg, **kwargs): 65 | return '000000' 66 | 67 | def mock_get_phone_fail(self, *args, **kwargs): 68 | raise Exception("Failed to get phone number") 69 | 70 | def mock_get_code_fail(self, *args, **kwargs): 71 | raise Exception("Failed to retreive code") 72 | 73 | def test_create_account_firefox_and_getsmscode(monkeypatch): 74 | monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_phone', mock_get_phone_getsmscode) 75 | monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_code', mock_get_code) 76 | 77 | driver = create_driver('firefox') 78 | # Test data 79 | sms_key = { 80 | "name": "getsmscode", 81 | "data": { 82 | "user": "username", 83 | "token": "your_api_key", 84 | } 85 | } 86 | username = "testuser" 87 | password = "testpassword" 88 | first_name = "John" 89 | last_name = "Doe" 90 | month = "1" 91 | day = "1" 92 | year = "2000" 93 | 94 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) 95 | assert email == f"{username}@gmail.com" 96 | assert password == "testpassword" 97 | 98 | def test_create_account_chrome_and_smspool(monkeypatch): 99 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) 100 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code) 101 | 102 | driver = create_driver('chrome') 103 | # Test data 104 | sms_key = { 105 | "name": "smspool", 106 | "data": { 107 | "token": "your_api_key", 108 | } 109 | } 110 | username = "testuser" 111 | password = "testpassword" 112 | first_name = "John" 113 | last_name = "Doe" 114 | month = "1" 115 | day = "1" 116 | year = "2000" 117 | 118 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) 119 | assert email == f"{username}@gmail.com" 120 | assert password == "testpassword" 121 | 122 | def test_create_account_chrome_and_fivesim(monkeypatch): 123 | monkeypatch.setattr('sms_services.fivesim.FiveSim.get_phone', mock_get_phone_fivesim) 124 | monkeypatch.setattr('sms_services.fivesim.FiveSim.get_code', mock_get_code) 125 | 126 | driver = create_driver('chrome') 127 | # Test data 128 | sms_key = { 129 | "name": "5sim", 130 | "data": { 131 | "token": "your_api_key", 132 | "service": "google" 133 | } 134 | } 135 | username = "testuser" 136 | password = "testpassword" 137 | first_name = "John" 138 | last_name = "Doe" 139 | month = "1" 140 | day = "1" 141 | year = "2000" 142 | 143 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) 144 | assert email == f"{username}@gmail.com" 145 | assert password == "testpassword" 146 | 147 | def test_create_account_phone_fail(monkeypatch): 148 | monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_phone', mock_get_phone_fail) 149 | 150 | driver = create_driver('firefox') 151 | # Test data 152 | sms_key = { 153 | "name": "getsmscode", 154 | "data": { 155 | "user": "username", 156 | "token": "your_api_key", 157 | } 158 | } 159 | username = "testuser" 160 | password = "testpassword" 161 | first_name = "John" 162 | last_name = "Doe" 163 | month = "1" 164 | day = "1" 165 | year = "2000" 166 | 167 | with pytest.raises(Exception, match="Failed to get phone number"): 168 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) 169 | assert email == None 170 | assert password == None 171 | 172 | def test_create_account_code_fail(monkeypatch): 173 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) 174 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code_fail) 175 | 176 | driver = create_driver('firefox') 177 | # Test data 178 | sms_key = { 179 | "name": "smspool", 180 | "data": { 181 | "token": "your_api_key", 182 | } 183 | } 184 | username = "testuser" 185 | password = "testpassword" 186 | first_name = "John" 187 | last_name = "Doe" 188 | month = "1" 189 | day = "1" 190 | year = "2000" 191 | 192 | with pytest.raises(Exception, match="Failed to retreive code"): 193 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) 194 | assert email == None 195 | assert password == None 196 | -------------------------------------------------------------------------------- /ninjemail/tests/test_email_outlook.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from unittest.mock import Mock, MagicMock 3 | from selenium.webdriver.common.keys import Keys 4 | from ..email_providers.outlook import create_account 5 | from ..utils.webdriver_utils import create_driver 6 | 7 | @pytest.fixture(autouse=True) 8 | def mock_outlook(monkeypatch): 9 | # Mock GeckoDriverManager and ChromeDriverManager installations 10 | monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', lambda *args, **kwargs: 'gecko_driver_path') 11 | monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', lambda *args, **kwargs: 'chrome_driver_path') 12 | 13 | # Mock WebDriver classes 14 | mock_firefox = Mock() 15 | mock_chrome = Mock() 16 | monkeypatch.setattr('selenium.webdriver.Firefox', lambda *args, **kwargs: mock_firefox) 17 | monkeypatch.setattr('selenium.webdriver.Chrome', lambda *args, **kwargs: mock_chrome) 18 | 19 | # Mock WebDriver methods 20 | mock_firefox.get = MagicMock() 21 | mock_chrome.get = MagicMock() 22 | mock_firefox.find_element = MagicMock(return_value=Mock()) 23 | mock_chrome.find_element = MagicMock(return_value=Mock()) 24 | mock_firefox.find_elements = MagicMock(return_value=[Mock()]) 25 | mock_chrome.find_elements = MagicMock(return_value=[Mock()]) 26 | mock_firefox.quit = MagicMock() 27 | mock_chrome.quit = MagicMock() 28 | 29 | # Mock WebDriverWait and expected_conditions 30 | mock_wait = MagicMock() 31 | monkeypatch.setattr('selenium.webdriver.support.ui.WebDriverWait', lambda *args, **kwargs: mock_wait) 32 | mock_wait.until = MagicMock(return_value=Mock()) 33 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.presence_of_element_located', lambda *args, **kwargs: MagicMock()) 34 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.element_to_be_clickable', lambda *args, **kwargs: MagicMock()) 35 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.visibility_of_element_located', lambda *args, **kwargs: MagicMock()) 36 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.frame_to_be_available_and_switch_to_it', lambda *args, **kwargs: MagicMock()) 37 | 38 | # Correctly mock Select class 39 | def mock_select_init(self, *args, **kwargs): 40 | self.select_by_index = MagicMock() 41 | self.select_by_visible_text = MagicMock() 42 | self.select_by_value = MagicMock() 43 | 44 | monkeypatch.setattr('selenium.webdriver.support.ui.Select.__init__', mock_select_init) 45 | 46 | # Mock Keys 47 | monkeypatch.setattr('selenium.webdriver.common.keys.Keys', Keys) 48 | 49 | # Mock time 50 | monkeypatch.setattr('time.sleep', MagicMock(())) 51 | 52 | # Mock logging 53 | monkeypatch.setattr('logging.info', MagicMock()) 54 | monkeypatch.setattr('logging.error', MagicMock()) 55 | 56 | # Mock sms services 57 | def mock_get_phone_getsmscode(self, *args, **kwargs): 58 | return '111111111' 59 | 60 | def mock_get_phone_smspool(self, *args, **kwargs): 61 | return 'ordeid', '111111111' 62 | 63 | def mock_get_code(self, *arg, **kwargs): 64 | return '000000' 65 | 66 | def mock_get_phone_fail(self, *args, **kwargs): 67 | raise Exception("Failed to get phone number") 68 | 69 | def mock_get_code_fail(self, *args, **kwargs): 70 | raise Exception("Failed to retreive code") 71 | 72 | def test_create_account_firefox(): 73 | 74 | driver = create_driver('firefox') 75 | # Test data 76 | username = "testuser" 77 | password = "testpassword" 78 | first_name = "John" 79 | last_name = "Doe" 80 | country = "us" 81 | month = "1" 82 | day = "1" 83 | year = "2000" 84 | hotmail = False 85 | 86 | email, password = create_account(driver, username, password, first_name, last_name, country, month, day, year, hotmail) 87 | assert email == f"{username}@outlook.com" 88 | assert password == "testpassword" 89 | 90 | def test_create_account_chrome(): 91 | 92 | driver = create_driver('chrome') 93 | # Test data 94 | username = "testuser" 95 | password = "testpassword" 96 | first_name = "John" 97 | last_name = "Doe" 98 | country="us" 99 | month = "1" 100 | day = "1" 101 | year = "2000" 102 | hotmail = False 103 | 104 | email, password = create_account(driver, username, password, first_name, last_name, country, month, day, year, hotmail) 105 | assert email == f"{username}@outlook.com" 106 | assert password == "testpassword" 107 | 108 | def test_create_hotmail_account(): 109 | 110 | driver = create_driver('chrome') 111 | # Test data 112 | 113 | username = "testuser" 114 | password = "testpassword" 115 | first_name = "John" 116 | last_name = "Doe" 117 | country = "us" 118 | month = "1" 119 | day = "1" 120 | year = "2000" 121 | hotmail = True 122 | 123 | email, password = create_account(driver, username, password, first_name, last_name, country, month, day, year, hotmail) 124 | assert email == f"{username}@hotmail.com" 125 | assert password == "testpassword" 126 | 127 | -------------------------------------------------------------------------------- /ninjemail/tests/test_email_yahoo.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from unittest.mock import Mock, MagicMock 3 | from selenium.webdriver.common.keys import Keys 4 | from ..email_providers.yahoo import create_account 5 | from ..utils.webdriver_utils import create_driver 6 | 7 | @pytest.fixture(autouse=True) 8 | def mock_yahoo(monkeypatch): 9 | # Mock GeckoDriverManager and ChromeDriverManager installations 10 | monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', lambda *args, **kwargs: 'gecko_driver_path') 11 | monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', lambda *args, **kwargs: 'chrome_driver_path') 12 | 13 | # Mock WebDriver classes 14 | mock_firefox = Mock() 15 | mock_chrome = Mock() 16 | monkeypatch.setattr('selenium.webdriver.Firefox', lambda *args, **kwargs: mock_firefox) 17 | monkeypatch.setattr('selenium.webdriver.Chrome', lambda *args, **kwargs: mock_chrome) 18 | 19 | # Mock WebDriver methods 20 | mock_firefox.get = MagicMock() 21 | mock_chrome.get = MagicMock() 22 | mock_firefox.current_url = '/create/success' 23 | mock_chrome.current_url = '/create/success' 24 | mock_firefox.find_element = MagicMock(return_value=Mock()) 25 | mock_chrome.find_element = MagicMock(return_value=Mock()) 26 | mock_firefox.find_elements = MagicMock(return_value=[Mock()]) 27 | mock_chrome.find_elements = MagicMock(return_value=[Mock()]) 28 | mock_firefox.quit = MagicMock() 29 | mock_chrome.quit = MagicMock() 30 | 31 | # Mock WebDriverWait and expected_conditions 32 | mock_wait = MagicMock() 33 | monkeypatch.setattr('selenium.webdriver.support.ui.WebDriverWait', lambda *args, **kwargs: mock_wait) 34 | mock_wait.until = MagicMock(return_value=Mock()) 35 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.presence_of_element_located', lambda *args, **kwargs: MagicMock()) 36 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.element_to_be_clickable', lambda *args, **kwargs: MagicMock()) 37 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.visibility_of_element_located', lambda *args, **kwargs: MagicMock()) 38 | monkeypatch.setattr('selenium.webdriver.support.expected_conditions.frame_to_be_available_and_switch_to_it', lambda *args, **kwargs: MagicMock()) 39 | 40 | # Correctly mock Select class 41 | def mock_select_init(self, *args, **kwargs): 42 | self.select_by_index = MagicMock() 43 | self.select_by_visible_text = MagicMock() 44 | self.select_by_value = MagicMock() 45 | 46 | monkeypatch.setattr('selenium.webdriver.support.ui.Select.__init__', mock_select_init) 47 | 48 | # Mock Keys 49 | monkeypatch.setattr('selenium.webdriver.common.keys.Keys', Keys) 50 | 51 | # Mock time 52 | monkeypatch.setattr('time.sleep', MagicMock(())) 53 | 54 | # Mock logging 55 | monkeypatch.setattr('logging.info', MagicMock()) 56 | monkeypatch.setattr('logging.error', MagicMock()) 57 | 58 | # Mock sms services 59 | def mock_get_phone_getsmscode(self, *args, **kwargs): 60 | return '111111111' 61 | 62 | def mock_get_phone_smspool(self, *args, **kwargs): 63 | return 'ordeid', '111111111' 64 | 65 | def mock_get_phone_fivesim(self, *args, **kwargs): 66 | return 'ordeid', '111111111' 67 | 68 | def mock_get_code(self, *arg, **kwargs): 69 | return '000000' 70 | 71 | def mock_get_phone_fail(self, *args, **kwargs): 72 | raise Exception("Failed to get phone number") 73 | 74 | def mock_get_code_fail(self, *args, **kwargs): 75 | raise Exception("Failed to retreive code") 76 | 77 | def test_create_account_firefox_and_getsmscode(monkeypatch): 78 | monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_phone', mock_get_phone_getsmscode) 79 | monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_code', mock_get_code) 80 | 81 | driver = create_driver('firefox') 82 | # Test data 83 | sms_key = { 84 | "name": "getsmscode", 85 | "data": { 86 | "user": "username", 87 | "token": "your_api_key", 88 | } 89 | } 90 | username = "testuser" 91 | password = "testpassword" 92 | first_name = "John" 93 | last_name = "Doe" 94 | month = "1" 95 | day = "1" 96 | year = "2000" 97 | myyahoo = False 98 | 99 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year, myyahoo) 100 | assert email == f"{username}@yahoo.com" 101 | assert password == "testpassword" 102 | 103 | def test_create_account_chrome_and_smspool(monkeypatch): 104 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) 105 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code) 106 | 107 | driver = create_driver('chrome') 108 | # Test data 109 | sms_key = { 110 | "name": "smspool", 111 | "data": { 112 | "token": "your_api_key", 113 | } 114 | } 115 | username = "testuser" 116 | password = "testpassword" 117 | first_name = "John" 118 | last_name = "Doe" 119 | month = "1" 120 | day = "1" 121 | year = "2000" 122 | myyahoo = False 123 | 124 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year, myyahoo) 125 | assert email == f"{username}@yahoo.com" 126 | assert password == "testpassword" 127 | 128 | def test_create_account_firefox_and_fivesim(monkeypatch): 129 | monkeypatch.setattr('sms_services.fivesim.FiveSim.get_phone', mock_get_phone_fivesim) 130 | monkeypatch.setattr('sms_services.fivesim.FiveSim.get_code', mock_get_code) 131 | 132 | driver = create_driver('firefox') 133 | # Test data 134 | sms_key = { 135 | "name": "5sim", 136 | "data": { 137 | "service": "yahoo", 138 | "token": "your_api_key", 139 | } 140 | } 141 | username = "testuser" 142 | password = "testpassword" 143 | first_name = "John" 144 | last_name = "Doe" 145 | month = "1" 146 | day = "1" 147 | year = "2000" 148 | myyahoo = False 149 | 150 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year, myyahoo) 151 | assert email == f"{username}@yahoo.com" 152 | assert password == "testpassword" 153 | 154 | def test_create_myyahoo_account(monkeypatch): 155 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) 156 | monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code) 157 | 158 | driver = create_driver('chrome') 159 | # Test data 160 | 161 | sms_key = { 162 | "name": "smspool", 163 | "data": { 164 | "token": "your_api_key", 165 | } 166 | } 167 | username = "testuser" 168 | password = "testpassword" 169 | first_name = "John" 170 | last_name = "Doe" 171 | month = "1" 172 | day = "1" 173 | year = "2000" 174 | myyahoo = True 175 | 176 | email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year, myyahoo) 177 | assert email == f"{username}@myyahoo.com" 178 | assert password == "testpassword" 179 | 180 | 181 | -------------------------------------------------------------------------------- /ninjemail/tests/test_sms_5sim.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import requests 3 | 4 | from ..sms_services.fivesim import FiveSim, APIError 5 | 6 | # Mocking requests.post 7 | @pytest.fixture 8 | def mock_requests_get(mocker): 9 | mock = mocker.patch("requests.get") 10 | mock.return_value.raise_for_status.return_value = None 11 | mock.return_value.json.return_value = {"success": True} 12 | return mock 13 | 14 | # Mocking time.sleep 15 | @pytest.fixture 16 | def mock_time_sleep(mocker): 17 | return mocker.patch("time.sleep") 18 | 19 | # Fixture to create an instance of FiveSim 20 | @pytest.fixture 21 | def fivesim(): 22 | return FiveSim(service="service_id", token="api_key", country="usa") 23 | 24 | def test_request_success(mock_requests_get, fivesim): 25 | response = fivesim.request("some_command") 26 | assert response == {"success": True} 27 | mock_requests_get.assert_called_once_with( 28 | "https://5sim.net/v1/user/some_command", 29 | headers = { 30 | 'Authorization': 'Bearer ' + 'api_key', 31 | } 32 | ) 33 | 34 | def test_request_failure(mock_requests_get, fivesim): 35 | mock_requests_get.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError 36 | with pytest.raises(APIError): 37 | fivesim.request("some_command") 38 | 39 | def test_get_phone(mock_requests_get, fivesim): 40 | mock_requests_get.return_value.json.return_value = { 41 | "phone": "+1234567890", 42 | "id": "order123" 43 | } 44 | phone, order_id = fivesim.get_phone() 45 | assert phone == "234567890" 46 | assert order_id == "order123" 47 | 48 | def test_get_code(mock_requests_get, fivesim): 49 | mock_requests_get.return_value.json.return_value = { 50 | "sms": [{"code" :"12345"}] 51 | } 52 | code = fivesim.get_code("order123") 53 | assert code == "12345" 54 | 55 | def test_get_phone_with_prefix(mock_requests_get, fivesim): 56 | mock_requests_get.return_value.json.return_value = { 57 | "phone": "+1234567890", 58 | "id": "order123" 59 | } 60 | phone, order_id = fivesim.get_phone(send_prefix=True) 61 | assert phone == "1234567890" 62 | assert order_id == "order123" 63 | 64 | def test_request_error_response(mock_requests_get, fivesim): 65 | mock_requests_get.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError 66 | with pytest.raises(APIError): 67 | fivesim.request("some_command") 68 | 69 | def test_get_phone_error_response(mock_requests_get, fivesim): 70 | mock_requests_get.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError 71 | 72 | with pytest.raises(APIError): 73 | fivesim.get_phone() 74 | 75 | def test_request_error_no_free_phones(mock_requests_get, fivesim): 76 | mock_response = mock_requests_get.return_value 77 | mock_response.text = "no free phones" 78 | 79 | with pytest.raises(APIError) as exc_info: 80 | fivesim.request('no_phone') 81 | assert str(exc_info.value) == '5Sim has no free phones' 82 | 83 | def test_request_error_not_enough_balance(mock_requests_get, fivesim): 84 | mock_response = mock_requests_get.return_value 85 | mock_response.text = "not enough user balance" 86 | 87 | with pytest.raises(APIError) as exc_info: 88 | fivesim.request('no_balance') 89 | assert str(exc_info.value) == 'Not enough balance' 90 | 91 | def test_get_code_error_response(mock_requests_get, mock_time_sleep, fivesim): 92 | mock_time_sleep.side_effect = Exception("Test exception") 93 | mock_requests_get.return_value.json.return_value = { 94 | "status": "CANCELLED", 95 | "sms": [] 96 | } 97 | with pytest.raises(Exception) as exc_info: 98 | fivesim.get_code("order123") 99 | assert str(exc_info.value) == "Test exception" 100 | 101 | -------------------------------------------------------------------------------- /ninjemail/tests/test_sms_getsmscode.py: -------------------------------------------------------------------------------- 1 | import re 2 | import pytest 3 | from unittest.mock import MagicMock, patch 4 | import requests 5 | from ..sms_services.getsmscode import GetsmsCode, APIError 6 | 7 | # Mocking requests.post 8 | @pytest.fixture 9 | def mock_requests_post(mocker): 10 | mock = mocker.patch("requests.post") 11 | mock.return_value.raise_for_status.return_value = None 12 | mock.return_value.text = "Success" 13 | return mock 14 | 15 | # Mocking time.sleep 16 | @pytest.fixture 17 | def mock_time_sleep(mocker): 18 | return mocker.patch("time.sleep") 19 | 20 | # Fixture to create an instance of GetsmsCode 21 | @pytest.fixture 22 | def gs(): 23 | return GetsmsCode(project="123", user="user", token="token", country="us") 24 | 25 | def test_initialization(gs): 26 | assert gs.user == "user" 27 | assert gs.token == "token" 28 | assert gs.project == "123" 29 | assert gs.country == "us" 30 | assert gs.prefix == "1" 31 | assert gs.API_URL == "http://api.getsmscode.com/usdo.php" 32 | 33 | def test_generate_generic(gs): 34 | phone = gs._generate_generic() 35 | assert phone.startswith("52") 36 | assert len(phone) == 8 37 | 38 | def test_get_endpoint(gs): 39 | assert gs.get_endpoint("us") == "usdo" 40 | assert gs.get_endpoint("hk") == "vndo" 41 | assert gs.get_endpoint("cn") == "do" 42 | 43 | @patch("requests.post") 44 | def test_request(mock_post, gs): 45 | mock_post.return_value.raise_for_status.return_value = None 46 | mock_post.return_value.text = "Success" 47 | response = gs.request(action="getmobile") 48 | assert response == "Success" 49 | 50 | @patch("requests.post") 51 | def test_get_phone(mock_post, gs): 52 | mock_post.return_value.raise_for_status.return_value = None 53 | mock_post.return_value.text = "234567" 54 | phone = gs.get_phone() 55 | assert phone == "234567" 56 | 57 | @patch("requests.post") 58 | def test_get_phone_with_prefix(mock_post, gs): 59 | mock_post.return_value.raise_for_status.return_value = None 60 | mock_post.return_value.text = "1234567" 61 | phone = gs.get_phone(send_prefix=True) 62 | assert phone == "1234567" 63 | 64 | @patch("requests.post") 65 | def test_get_code(mock_post, gs): 66 | mock_post.return_value.raise_for_status.return_value = None 67 | mock_post.return_value.text = "Success|12345" 68 | code = gs.get_code("1234567") 69 | assert code == "12345" 70 | 71 | @patch("requests.post") 72 | def test_request_failure(mock_post, gs): 73 | mock_post.side_effect = requests.exceptions.RequestException("Network error") 74 | with pytest.raises(requests.exceptions.RequestException): 75 | gs.request(action="getmobile") 76 | 77 | @patch("requests.post") 78 | def test_api_error_response_message(mock_post, gs): 79 | mock_post.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError() 80 | mock_post.return_value.text = "Error|Invalid request" 81 | with pytest.raises(requests.exceptions.HTTPError) as exc_info: 82 | gs.request(action="getmobile") 83 | assert str(exc_info.value) == "" 84 | 85 | @patch("requests.post") 86 | def test_no_code_found(mock_post, gs): 87 | mock_post.return_value.text = "Success|" 88 | with pytest.raises(AssertionError): 89 | gs.get_code("1234567") 90 | 91 | @patch("requests.post") 92 | def test_request_timeout(mock_post, gs): 93 | mock_post.side_effect = requests.exceptions.Timeout() 94 | with pytest.raises(requests.exceptions.Timeout): 95 | gs.request(action="getmobile") 96 | -------------------------------------------------------------------------------- /ninjemail/tests/test_sms_smspool.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import requests 3 | from unittest.mock import MagicMock, patch 4 | 5 | from ..sms_services.smspool import SMSPool, APIError 6 | 7 | # Mocking requests.post 8 | @pytest.fixture 9 | def mock_requests_post(mocker): 10 | mock = mocker.patch("requests.post") 11 | mock.return_value.raise_for_status.return_value = None 12 | mock.return_value.json.return_value = {"success": True} 13 | return mock 14 | 15 | # Mocking time.sleep 16 | @pytest.fixture 17 | def mock_time_sleep(mocker): 18 | return mocker.patch("time.sleep") 19 | 20 | # Fixture to create an instance of SMSPool 21 | @pytest.fixture 22 | def sms_pool(): 23 | return SMSPool(service="service_id", token="api_key", country="hk") 24 | 25 | def test_request_success(mock_requests_post, sms_pool): 26 | response = sms_pool.request("some_command") 27 | assert response == {"success": True} 28 | mock_requests_post.assert_called_once_with( 29 | "http://api.smspool.net/some_command", 30 | params={"key": "api_key"} 31 | ) 32 | 33 | def test_request_failure(mock_requests_post, sms_pool): 34 | mock_requests_post.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError 35 | with pytest.raises(requests.exceptions.HTTPError): 36 | sms_pool.request("some_command") 37 | 38 | def test_get_phone(mock_requests_post, sms_pool): 39 | mock_requests_post.return_value.json.return_value = { 40 | "success": True, 41 | "number": "1234567890", 42 | "phonenumber": "234567890", 43 | "order_id": "order123" 44 | } 45 | phone, order_id = sms_pool.get_phone() 46 | assert phone == "234567890" 47 | assert order_id == "order123" 48 | 49 | def test_get_code(mock_requests_post, sms_pool): 50 | mock_requests_post.return_value.json.return_value = { 51 | "success": True, 52 | "sms": "12345" 53 | } 54 | code = sms_pool.get_code("order123") 55 | assert code == "12345" 56 | 57 | def test_get_phone_with_prefix(mock_requests_post, sms_pool): 58 | mock_requests_post.return_value.json.return_value = { 59 | "success": True, 60 | "number": "1234567890", 61 | "phonenumber": "234567890", 62 | "order_id": "order123" 63 | } 64 | phone, order_id = sms_pool.get_phone(send_prefix=True) 65 | assert phone == "1234567890" 66 | assert order_id == "order123" 67 | 68 | def test_request_error_response(mock_requests_post, sms_pool): 69 | mock_requests_post.return_value.json.return_value = { 70 | "success": False, 71 | "message": "Error message" 72 | } 73 | with pytest.raises(APIError) as exc_info: 74 | sms_pool.request("some_command") 75 | assert str(exc_info.value) == "Error message" 76 | 77 | def test_get_phone_error_response(mock_requests_post, sms_pool): 78 | mock_requests_post.return_value.json.return_value = { 79 | "success": False, 80 | "message": "Error message" 81 | } 82 | with pytest.raises(APIError) as exc_info: 83 | sms_pool.get_phone() 84 | assert str(exc_info.value) == "Error message" 85 | 86 | def test_get_code_error_response(mock_requests_post, mock_time_sleep, sms_pool): 87 | mock_time_sleep.side_effect = Exception("Test exception") 88 | mock_requests_post.return_value.json.return_value = { 89 | "success": False, 90 | "message": "Error message" 91 | } 92 | with pytest.raises(Exception) as exc_info: 93 | sms_pool.get_code("order123") 94 | assert str(exc_info.value) == "Test exception" 95 | -------------------------------------------------------------------------------- /ninjemail/tests/test_utils.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from faker import Faker 3 | 4 | from ..utils import CountryProvider, get_birthdate, generate_missing_info 5 | 6 | 7 | class TestCountryProvider: 8 | def test_country_returns_string(self): 9 | """Tests if CountryProvider.country returns a string.""" 10 | fake = Faker() 11 | fake.add_provider(CountryProvider) 12 | country = fake.country() 13 | assert isinstance(country, str) 14 | 15 | 16 | class TestGetBirthdate: 17 | def test_birthdate_split_correctly(self): 18 | """Tests if get_birthdate splits the birthdate string correctly.""" 19 | birthdate = "1990-12-31" 20 | month, day, year = get_birthdate(birthdate) 21 | assert month == "1990" 22 | assert day == "12" 23 | assert year == "31" 24 | 25 | def test_birthdate_split_invalid_format(self): 26 | """Tests if get_birthdate raises an error for invalid format.""" 27 | with pytest.raises(IndexError): 28 | get_birthdate("invalid_format") 29 | 30 | 31 | class TestGenerateMissingInfo: 32 | def test_generate_all_missing(self): 33 | """Tests if generate_missing_info fills all missing information.""" 34 | username, password, first_name, last_name, country, birthdate = generate_missing_info("", "", "", "", "", "") 35 | assert username 36 | assert password 37 | assert first_name 38 | assert last_name 39 | assert country 40 | assert birthdate 41 | 42 | def test_generate_partial_missing(self): 43 | """Tests if generate_missing_info fills only missing information.""" 44 | username = "test_user" 45 | password = "strong_password" 46 | first_name = "John" 47 | last_name = "Doe" 48 | country = "USA" 49 | birthdate = "1980-01-01" 50 | filled_info = generate_missing_info(username, password, first_name, last_name, country, birthdate) 51 | assert username == "test_user" 52 | assert password == "strong_password" 53 | assert first_name == "John" 54 | assert last_name == "Doe" 55 | assert country == "USA" 56 | assert birthdate == "1980-01-01" 57 | 58 | def test_uses_faker_for_generated_data(self): 59 | """Tests if generate_missing_info uses Faker for generated data.""" 60 | fake1 = Faker() 61 | fake2 = Faker() 62 | fake1.add_provider(CountryProvider) 63 | fake2.add_provider(CountryProvider) 64 | 65 | # Generate first names with different Fakers 66 | username, _, first_name1, _, _, _ = generate_missing_info("", "", "", "", "", "") 67 | _, _, first_name2, _, _, _ = generate_missing_info("", "", "", "", "", "") 68 | 69 | # Assert first names are different (likely from different Fakers) 70 | assert first_name1 != first_name2 71 | -------------------------------------------------------------------------------- /ninjemail/tests/test_webdriver_utils.py: -------------------------------------------------------------------------------- 1 | from unittest.mock import MagicMock 2 | import pytest 3 | from selenium.webdriver import Firefox, Chrome 4 | import undetected_chromedriver as uc 5 | from ..utils.webdriver_utils import create_driver 6 | 7 | @pytest.fixture(autouse=True) 8 | def mock_driver_manager_installations(monkeypatch): 9 | def mock_gecko_install(*args, **kwargs): 10 | return 'gecko_driver_path' 11 | 12 | def mock_chrome_install(*args, **kwargs): 13 | return 'chrome_driver_path' 14 | 15 | def mock_firefox_service(*args, **kwargs): 16 | return None 17 | 18 | def mock_chrome_service(*args, **kwargs): 19 | return None 20 | 21 | def mock_firefox(*args, **kwargs): 22 | pass 23 | 24 | def mock_chrome(*args, **kwargs): 25 | pass 26 | 27 | def mock_firefox_quit(self): 28 | pass 29 | 30 | def mock_chrome_quit(self): 31 | pass 32 | 33 | def mock_firefox_addon(*args, **kwargs): 34 | pass 35 | 36 | monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', mock_gecko_install) 37 | monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', mock_chrome_install) 38 | monkeypatch.setattr('selenium.webdriver.firefox.service.Service.__init__', mock_firefox_service) 39 | monkeypatch.setattr('selenium.webdriver.chrome.service.Service.__init__', mock_chrome_service) 40 | monkeypatch.setattr('selenium.webdriver.Firefox.__init__', mock_firefox) 41 | monkeypatch.setattr('selenium.webdriver.Chrome.__init__', mock_chrome) 42 | monkeypatch.setattr('undetected_chromedriver.Chrome.__init__', mock_chrome) 43 | monkeypatch.setattr('selenium.webdriver.Firefox.quit', mock_firefox_quit) 44 | monkeypatch.setattr('selenium.webdriver.Firefox.install_addon', mock_firefox_addon) 45 | monkeypatch.setattr('selenium.webdriver.Firefox.get', MagicMock()) 46 | monkeypatch.setattr('selenium.webdriver.Firefox.find_element', MagicMock()) 47 | monkeypatch.setattr('selenium.webdriver.Chrome.get', MagicMock()) 48 | monkeypatch.setattr('selenium.webdriver.Chrome.quit', mock_chrome_quit) 49 | monkeypatch.setattr('undetected_chromedriver.Chrome.quit', mock_chrome_quit) 50 | 51 | monkeypatch.setattr('time.sleep', MagicMock(())) 52 | 53 | 54 | def test_create_firefox_driver_no_proxy_no_captcha(): 55 | driver = create_driver('firefox') 56 | assert isinstance(driver, Firefox) 57 | driver.quit() 58 | 59 | 60 | def test_create_chrome_driver_no_proxy_no_captcha(): 61 | driver = create_driver('chrome') 62 | assert isinstance(driver, Chrome) 63 | driver.quit() 64 | 65 | def test_create_undetected_chrome_driver(): 66 | driver = create_driver('undetected-chrome') 67 | assert isinstance(driver, uc.Chrome) 68 | driver.quit() 69 | 70 | def test_create_undetected_chrome_driver_with_proxy_and_capsolver(): 71 | driver = create_driver('undetected-chrome', captcha_extension=True, proxy='http://10.10.10.1:2020', captcha_key={'name': 'capsolver', 'key': 'test_key'}) 72 | assert isinstance(driver, uc.Chrome) 73 | driver.quit() 74 | 75 | def test_create_undetected_chrome_driver_with_proxy_and_nopecha(): 76 | driver = create_driver('undetected-chrome', captcha_extension=True, proxy='http://10.10.10.1:2020', captcha_key={'name': 'nopecha', 'key': 'test_key'}) 77 | assert isinstance(driver, uc.Chrome) 78 | driver.quit() 79 | 80 | def test_create_undetected_chrome_driver_with_auth_proxy_and_nopecha(): 81 | driver = create_driver('undetected-chrome', captcha_extension=True, proxy='http://user:pass@10.10.10.1:2020', captcha_key={'name': 'nopecha', 'key': 'test_key'}) 82 | assert isinstance(driver, uc.Chrome) 83 | driver.quit() 84 | 85 | def test_create_undetected_chrome_driver_with_auth_proxy(): 86 | driver = create_driver('undetected-chrome', captcha_extension=False, proxy='http://user:pass@10.10.10.1:2020') 87 | assert isinstance(driver, uc.Chrome) 88 | driver.quit() 89 | 90 | def test_create_firefox_driver_with_proxy(): 91 | proxy_url = 'http://127.0.0.1:8080' 92 | 93 | driver = create_driver('firefox', proxy=proxy_url) 94 | assert isinstance(driver, Firefox) 95 | 96 | driver.quit() 97 | 98 | 99 | def test_create_chrome_driver_with_proxy(): 100 | proxy_url = 'http://127.0.0.1:8080' 101 | 102 | driver = create_driver('chrome', proxy=proxy_url) 103 | assert isinstance(driver, Chrome) 104 | driver.quit() 105 | 106 | def test_create_chrome_driver_with_auth_proxy(): 107 | proxy_url = 'http://user:pass@127.0.0.1:8080' 108 | 109 | driver = create_driver('chrome', proxy=proxy_url) 110 | assert isinstance(driver, Chrome) 111 | driver.quit() 112 | 113 | def test_create_chrome_driver_with_proxy_and_nopecha(): 114 | driver = create_driver('chrome', captcha_extension=True, proxy='http://10.10.10.1:2020', captcha_key={'name': 'nopecha', 'key': 'test_key'}) 115 | assert isinstance(driver, Chrome) 116 | driver.quit() 117 | 118 | def test_create_chrome_driver_with_proxy_and_capsolver(): 119 | driver = create_driver('chrome', captcha_extension=True, proxy='http://10.10.10.1:2020', captcha_key={'name': 'capsolver', 'key': 'test_key'}) 120 | assert isinstance(driver, Chrome) 121 | driver.quit() 122 | 123 | def test_create_firefox_driver_with_captcha_extension(): 124 | 125 | driver = create_driver('firefox', captcha_extension=True, captcha_key={'name': 'capsolver', 'key': 'test_key'}) 126 | assert isinstance(driver, Firefox) 127 | driver.quit() 128 | 129 | 130 | def test_unsupported_browser(): 131 | with pytest.raises(ValueError): 132 | create_driver('safari') 133 | -------------------------------------------------------------------------------- /ninjemail/utils/__init__.py: -------------------------------------------------------------------------------- 1 | from faker import Faker 2 | from faker.providers import BaseProvider 3 | import secrets 4 | import string 5 | import random 6 | 7 | 8 | class CountryProvider(BaseProvider): 9 | def country(self): 10 | """ 11 | Generate a random country name. 12 | 13 | Returns: 14 | str: A random country name. 15 | """ 16 | countries = [ 17 | "Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua and Barbuda", "Argentina", "Armenia", 18 | "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", 19 | "Belgium", "Belize", "Benin", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Brazil", 20 | "Brunei", "Bulgaria", "Burkina Faso", "Burundi", "Cabo Verde", "Cambodia", "Cameroon", "Canada", 21 | "Central African Republic", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo, Democratic Republic of the", 22 | "Congo, Republic of the", "Costa Rica", "Cote d'Ivoire", "Croatia", "Cuba", "Cyprus", "Czech Republic", 23 | "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", 24 | "Eritrea", "Estonia", "Eswatini", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Gambia", "Georgia", 25 | "Germany", "Ghana", "Greece", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", 26 | "Honduras", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", 27 | "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", 28 | "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Madagascar", 29 | "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", 30 | "Micronesia", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar (Burma)", 31 | "Namibia", "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger", "Nigeria", "North Korea", 32 | "North Macedonia", "Norway", "Oman", "Pakistan", "Palau", "Palestine", "Panama", "Papua New Guinea", 33 | "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Qatar", "Romania", "Russia", "Rwanda", "Saint Kitts and Nevis", 34 | "Saint Lucia", "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Sao Tome and Principe", 35 | "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", 36 | "Solomon Islands", "Somalia", "South Africa", "South Korea", "South Sudan", "Spain", "Sri Lanka", "Sudan", 37 | "Suriname", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste", 38 | "Togo", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", 39 | "United Arab Emirates", "United Kingdom", "United States of America", "Uruguay", "Uzbekistan", "Vanuatu", 40 | "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe" 41 | ] 42 | return self.random_element(countries) 43 | 44 | def get_birthdate(birthdate): 45 | birthdate_split = birthdate.split('-') 46 | 47 | return birthdate_split[0], birthdate_split[1], birthdate_split[2] 48 | 49 | def generate_missing_info(username, password, first_name, last_name, country, birthdate): 50 | """ 51 | Generate missing information for a user. 52 | 53 | This function takes in various user information as parameters and generates missing values 54 | for them if they are not provided. It uses the Faker library to generate fake data when needed. 55 | 56 | Args: 57 | username (str): The username of the user. 58 | password (str): The password of the user. 59 | first_name (str): The first name of the user. 60 | last_name (str): The last name of the user. 61 | country (str): The country of the user. 62 | birthdate (str): The birthdate of the user in the format 'MM-DD-YYYY'. 63 | 64 | Returns: 65 | tuple: A tuple containing the generated or provided values for the username, password, 66 | first name, last name, country, and birthdate in the same order. 67 | 68 | """ 69 | fake = Faker() 70 | fake.add_provider(CountryProvider) 71 | 72 | if not password: 73 | characters = string.ascii_letters + string.digits + string.punctuation 74 | password = ''.join(secrets.choice(characters) for _ in range(random.randint(8, 12))) 75 | 76 | if not first_name: 77 | first_name = fake.first_name() 78 | 79 | if not last_name: 80 | last_name = fake.last_name() 81 | 82 | if not country: 83 | country = fake.country() 84 | 85 | if not birthdate: 86 | birthdate = fake.date_of_birth(minimum_age=18) 87 | birthdate = f"{birthdate.month}-{birthdate.day}-{birthdate.year}" 88 | 89 | if not username: 90 | first_initial = first_name[0].lower() 91 | last_name = last_name.replace(" ", "").lower() 92 | year = birthdate.split('-')[2] 93 | 94 | random_number = random.randint(100, 999) 95 | username = f"{first_initial}{last_name}{year}{random_number}" 96 | 97 | return username, password, first_name, last_name, country, birthdate 98 | 99 | -------------------------------------------------------------------------------- /ninjemail/utils/proxy_auth_ext/background.js: -------------------------------------------------------------------------------- 1 | 2 | var config = { 3 | mode: "fixed_servers", 4 | rules: { 5 | singleProxy: { 6 | scheme: "http", 7 | host: "", 8 | port: parseInt() 9 | }, 10 | bypassList: ["localhost"] 11 | } 12 | }; 13 | 14 | chrome.proxy.settings.set({value: config, scope: "regular"}, function() {}); 15 | 16 | function callbackFn(details) { 17 | return { 18 | authCredentials: { 19 | username: "", 20 | password: "" 21 | } 22 | }; 23 | } 24 | 25 | chrome.webRequest.onAuthRequired.addListener( 26 | callbackFn, 27 | {urls: [""]}, 28 | ['blocking'] 29 | ); 30 | 31 | -------------------------------------------------------------------------------- /ninjemail/utils/proxy_auth_ext/manifest.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "version": "1.0.0", 4 | "manifest_version": 3, 5 | "name": "Chrome Proxy", 6 | "permissions": [ 7 | "Proxy", 8 | "Tabs", 9 | "unlimitedStorage", 10 | "Storage", 11 | "", 12 | "webRequest", 13 | "webRequestBlocking" 14 | ], 15 | "background": { 16 | "scripts": ["background.js"] 17 | }, 18 | "minimum_chrome_version":"76.0.0" 19 | } 20 | -------------------------------------------------------------------------------- /ninjemail/utils/web_helpers.py: -------------------------------------------------------------------------------- 1 | # utils/web_helpers.py 2 | from typing import Tuple 3 | from selenium.webdriver.remote.webdriver import WebDriver 4 | from selenium.webdriver.remote.webelement import WebElement 5 | from selenium.webdriver.support import expected_conditions as EC 6 | from selenium.webdriver.support.ui import WebDriverWait 7 | from selenium.common.exceptions import WebDriverException 8 | 9 | def safe_click(element: WebElement) -> None: 10 | """Click element with JavaScript as fallback""" 11 | try: 12 | element.click() 13 | except WebDriverException: 14 | pass 15 | 16 | def wait_and_click(driver: WebDriver, 17 | by: Tuple[str, str], 18 | timeout: int = 10) -> None: 19 | """Wait for element to be clickable and click it""" 20 | element = WebDriverWait(driver, timeout).until( 21 | EC.element_to_be_clickable(by) 22 | ) 23 | safe_click(element) 24 | 25 | def set_input_value(driver: WebDriver, 26 | selector: Tuple[str, str], 27 | value: str) -> None: 28 | """Set input value with JavaScript to ensure proper update""" 29 | element = WebDriverWait(driver, 10).until( 30 | EC.presence_of_element_located(selector) 31 | ) 32 | element.send_keys(value) 33 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | selenium 2 | webdriver-manager 3 | requests 4 | fake_useragent 5 | free-proxy 6 | toml 7 | Faker 8 | pytest 9 | pytest-mock 10 | pytest-cov 11 | undetected-chromedriver 12 | --------------------------------------------------------------------------------