Skip to content

Commit

Permalink
Merge pull request #8 from Apophis52/master
Browse files Browse the repository at this point in the history
Added email verification
  • Loading branch information
cubicbyte authored Aug 25, 2023
2 parents 4d92dbb + 61e1e3b commit 2704b76
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 33 deletions.
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ A python script on selenium to automatically create Reddit accounts.
- [TODO](#todo)
- [Getting started](#getting-started)
- [Script Installation](#script-installation)
- [Script Usage](#command-line-usage)
- [Script Usage](#script-usage)
- [Package Installation](#package-installation)
- [Package Usage](#package-usage)
- [Package Usage](#package-usage-example)
- [Requirements](#requirements)
- [Contributing](#contributing)
- [License](#license)
Expand All @@ -23,22 +23,25 @@ A python script on selenium to automatically create Reddit accounts.

## Features
- **Automatic captcha bypass**: The script automatically solves captchas during the account creation process.
- **Automatic email verification**: The script automatically verifies the email address used for the account.
- **Proxy Support**: Since reddit allows you to create 1 account per IP every 10 minutes, this is very important.
- **Resilience**: The script is able to handle most errors that may occur during the account creation process.

## Quick info

You still need to activate the accounts via email. But it doesn't take much time.

Firefox should be installed on your system for the script to work.

It is recommended to use proxies, because you can only create 1 account per IP in 10 minutes. See file **proxies.txt** or run `python run_tor.py`

To access the auto-generated email, visit https://1secmail.com

If you are not using your email, you should not show anyone the email address generated by the program. Having the address of this email, anyone can access it.

## TODO:
- [x] Add automatic browser driver download
- [x] Add Tor support for easier proxy management
- [x] Make this a python package
- [ ] Automatic email verification
- [x] Automatic email verification
- [ ] Handle error when sub is not available

# Getting started
Expand Down Expand Up @@ -66,7 +69,7 @@ pip install -r requirements-cli.txt
> **Note** **You need to use Tor (not browser) or proxy, because you can only create 1 account per IP in 10 minutes**
#### Using Tor (recommended)
#### Using Tor (recommended for beginners)
Run this command and follow the instructions:
```shell
python run_tor.py
Expand All @@ -75,9 +78,11 @@ python run_tor.py
#### Using proxies
Add your proxies to the proxies.txt file

### Configuration
### Configuring

Open the `config.py` file and put your email to be used on your accounts. Other settings are optional.
Configuring is not needed. But if you want, you can change the settings in the [config.py](config.py) file.

### Starting

1. Run the script:

Expand Down Expand Up @@ -142,7 +147,7 @@ protect_account(username, password)
```

Using proxy:

```python
from reddit_account_generator import create_account, protect_account, install_driver
from reddit_account_generator.proxies import TorProxy
Expand Down
6 changes: 2 additions & 4 deletions config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

# You can set here your email if you want, but in that case you need to manually verify account
EMAIL = ''

PROXIES_FILE = 'proxies.txt'
Expand All @@ -10,7 +11,7 @@
HIDE_BROWSER = False
MAX_RETRIES = 10 # Max retries for creating/protecting account
# You can set to False if you have Firefox installed
BUILTIN_DRIVER = True
BUILTIN_DRIVER = False
LOG_LEVEL = 'DEBUG' # DEBUG, INFO, WARNING, ERROR, CRITICAL

# Tor proxy config
Expand All @@ -20,6 +21,3 @@
TOR_CONTROL_PORT = 9051
TOR_PASSWORD = 'Passwort'
TOR_DELAY = 5


assert EMAIL != '', 'Please enter your email in config.py file'
28 changes: 24 additions & 4 deletions create_accounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from selenium.common.exceptions import NoSuchWindowException, WebDriverException

from reddit_account_generator import maker, protector, create_account, protect_account, install_driver
from reddit_account_generator import maker, protector, verifier, create_account, protect_account, verify_email, install_driver
from reddit_account_generator.proxies import DefaultProxy, TorProxy, EmptyProxy
from reddit_account_generator.utils import *
from reddit_account_generator.exceptions import *
Expand All @@ -26,12 +26,16 @@
logging.warning('Coloredlogs is not installed. Install it with "pip install coloredlogs" to get cool logs!')

# Set config variables
# TODO: Make this better
maker.PAGE_LOAD_TIMEOUT_S = PAGE_LOAD_TIMEOUT_S
maker.DRIVER_TIMEOUT_S = DRIVER_TIMEOUT_S
maker.MICRO_DELAY_S = MICRO_DELAY_S
protector.PAGE_LOAD_TIMEOUT_S = PAGE_LOAD_TIMEOUT_S
protector.DRIVER_TIMEOUT_S = DRIVER_TIMEOUT_S
protector.MICRO_DELAY_S = MICRO_DELAY_S
verifier.PAGE_LOAD_TIMEOUT_S = PAGE_LOAD_TIMEOUT_S
verifier.DRIVER_TIMEOUT_S = DRIVER_TIMEOUT_S
verifier.MICRO_DELAY_S = MICRO_DELAY_S

if BUILTIN_DRIVER:
# Install firefox driver binary
Expand Down Expand Up @@ -83,7 +87,11 @@ def save_account(email: str, username: str, password: str):

while retries < MAX_RETRIES:
try:
username, password = create_account(EMAIL, proxies=proxy_, hide_browser=HIDE_BROWSER)
email, username, password = create_account(
email=EMAIL or None,
proxies=proxy_,
hide_browser=HIDE_BROWSER
)
break

except UsernameTakenException:
Expand Down Expand Up @@ -117,14 +125,14 @@ def save_account(email: str, username: str, password: str):
_logger.error('An error occurred during account creation. Exiting...')
exit(1)

save_account(EMAIL, username, password)
save_account(email, username, password)
_logger.info('Account created! Protecting account...')

# Try to protect account
for i in range(MAX_RETRIES):
try:
protect_account(username, password, hide_browser=HIDE_BROWSER)
_logger.info('Account protected!\n')
_logger.info('Account protected!')
break

except IncorrectUsernameOrPasswordException:
Expand All @@ -136,4 +144,16 @@ def save_account(email: str, username: str, password: str):
else:
_logger.error('Account protection failed. Skipping...')

if not EMAIL:
for i in range(MAX_RETRIES):
try:
verify_email(email)
_logger.info('Email verified!\n')
break
except WebDriverException as e:
_logger.error(e)
_logger.error('An error occurred during email verification. Trying again... [%s/%s]', i+1, MAX_RETRIES)
else:
_logger.error('Email verification failed. Skipping...')

_logger.info('Done!')
1 change: 1 addition & 0 deletions reddit_account_generator/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from .maker import create_account
from .protector import protect_account
from .verifier import verify_email


def install_driver():
Expand Down
2 changes: 1 addition & 1 deletion reddit_account_generator/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.1.1'
__version__ = '1.2.0'
3 changes: 3 additions & 0 deletions reddit_account_generator/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ class SessionExpiredException(Exception):
class IncorrectUsernameOrPasswordException(Exception):
pass

class EmailVerificationException(Exception):
pass

NetworkException = (RecaptchaException, IPCooldownException, TimeoutException)
16 changes: 9 additions & 7 deletions reddit_account_generator/maker.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import time
import logging

from tempmail import EMail
from selenium.common.exceptions import TimeoutException, WebDriverException, NoSuchElementException, ElementClickInterceptedException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
Expand All @@ -17,8 +18,8 @@
_logger = logging.getLogger(__name__)


def create_account(email: str, username: str | None = None, password: str | None = None,
proxies: dict[str, str] | None = None, hide_browser: bool = True) -> tuple[str, str]:
def create_account(email: str | None = None, username: str | None = None, password: str | None = None,
proxies: dict[str, str] | None = None, hide_browser: bool = True) -> tuple[str, str, str]:
"""Create a Reddit account."""

_logger.info('Creating reddit account')
Expand All @@ -27,6 +28,9 @@ def create_account(email: str, username: str | None = None, password: str | None
if PAGE_LOAD_TIMEOUT_S is not None:
driver.set_page_load_timeout(PAGE_LOAD_TIMEOUT_S)

if email is None:
email = EMail().address

if password is None:
password = generate_password()

Expand Down Expand Up @@ -113,7 +117,7 @@ def create_account(email: str, username: str | None = None, password: str | None
if 'character' in password_err.text.lower():
raise PasswordLengthException(password_err.text)
raise Exception(password_err.text)

# Solve captcha
_logger.debug('Solving captcha')
WebDriverWait(driver, DRIVER_TIMEOUT_S).until(EC.element_to_be_clickable((By.XPATH, '//iframe[@title="reCAPTCHA"]')))
Expand Down Expand Up @@ -150,9 +154,7 @@ def create_account(email: str, username: str | None = None, password: str | None

# Account created!

except Exception as e: # quit driver if error occurs
finally: # quit driver if error occurs
driver.quit()
raise e

driver.quit()
return username, password
return email, username, password
7 changes: 2 additions & 5 deletions reddit_account_generator/protector.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def protect_account(username: str, password: str,
driver.get('https://www.reddit.com/login/')
except WebDriverException:
raise TimeoutException('Website takes too long to load. Probably a problem with the proxy.')

# Enter username and password
_logger.debug('Entering username and password')
username_input = driver.find_element(By.ID, 'loginUsername')
Expand Down Expand Up @@ -100,8 +100,5 @@ def protect_account(username: str, password: str,

# Done!

except Exception as e: # quit driver if error occurs
finally: # quit driver if error occurs
driver.quit()
raise e

driver.quit()
4 changes: 2 additions & 2 deletions reddit_account_generator/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def setup_firefox_driver(proxies: dict[str, str] | None = None, hide_browser: bo
options.set_preference('network.proxy.socks_port', int(socks_port))
options.set_preference('network.proxy.socks_remote_dns', False)

return webdriver.Firefox(options=options, service_log_path=os.devnull)
return webdriver.Firefox(options=options)


def try_to_click(element: WebElement, delay: int | float = 0.5, max_tries: int = 20) -> bool:
Expand All @@ -112,4 +112,4 @@ def try_to_click(element: WebElement, delay: int | float = 0.5, max_tries: int =
except:
retries += 1
time.sleep(delay)
raise TimeoutException(f'Could not click element after {max_tries} tries.')
raise TimeoutException(f'Could not click element after {max_tries} tries.')
58 changes: 58 additions & 0 deletions reddit_account_generator/verifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import logging

import requests
from tempmail import EMail

from .exceptions import EmailVerificationException

_logger = logging.getLogger(__name__)


def verify_email(email: str, proxies: dict[str, str] | None = None):
_logger.info('Verifying reddit account email')

# Get verification link
link = get_verification_link(email)
direct_link = get_direct_verification_link(link)

_logger.debug('Verifying email')
resp = requests.post(direct_link, headers={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/117.0'
}, proxies=proxies)

if resp.status_code != 200:
if 'EMAIL_ALREADY_VERIFIED' not in resp.text:
raise EmailVerificationException(resp.text)

_logger.warning('Email is already verified')


def get_verification_link(email: str) -> str:
try:
email_ = EMail(email)
except ValueError:
raise ValueError('Verification of this email is not supported.')

_logger.debug('Waiting for email...')
msg = email_.wait_for_message(filter=lambda m: 'reddit' in m.subject.lower())

# Get link
start = msg.body.index('https://www.reddit.com/verification/')
end = msg.body.index('"', start)
link = msg.body[start:end]

return link


def get_direct_verification_link(link: str) -> str:
"""Create a direct verification link from a verification link."""

start = link.index('verification/') + len('verification/')
end = link.index('?', start)
token = link[start:end]

start = link.index('correlation_id=') + len('correlation_id=')
end = link.index('&', start)
correlation_id = link[start:end]

return f'https://www.reddit.com/api/v1/verify_email/{token}.json?correlation_id={correlation_id}&ref_campaign=verify_email'
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ selenium-recaptcha-solver >=1.4.0, <=1.9.0
random-username >=1.0.0, <=1.0.2
webdriverdownloader >=1.0.0, <=1.1.0.3
stem >=1.8.0, <=1.8.2
static-ffmpeg >=2.3, <=2.5
static-ffmpeg >=2.3, <=2.5
tempmail-python==2.3.0
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def get_version(ver_file: str) -> str: # Credits to pyTelegramBotAPI setup.py
'webdriverdownloader >=1.0.0, <=1.1.0.3',
'stem >=1.8.0, <=1.8.2',
'static-ffmpeg >=2.3, <=2.5',
'tempmail-python==2.3.0',
],
classifiers=[
'Development Status :: 5 - Production/Stable',
Expand Down

0 comments on commit 2704b76

Please sign in to comment.