diff --git a/.gitignore b/.gitignore index d1f11ae..ab1faa8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,14 @@ __pycache__ find.py *.log *.egg-info + +.idea/ + +smstoken.txt + +google/protobuf/.DS_Store + +google/.DS_Store +/google/ + +.DS_Store diff --git a/authgateway.proto b/authgateway.proto new file mode 100644 index 0000000..9c9426b --- /dev/null +++ b/authgateway.proto @@ -0,0 +1,240 @@ +syntax = "proto3"; + +package tinder.services.authgateway; + +import "google/protobuf/wrappers.proto"; +import "google/protobuf/timestamp.proto"; + +option java_multiple_files = true; +option java_package = "com.tinder.generated.model.services.shared.authgateway"; + +message MetaProto { + google.protobuf.Timestamp upstream_time = 1; + google.protobuf.Timestamp start_time = 2; +} + +message GetPhoneState { + google.protobuf.StringValue refresh_token = 1; +} + +message ValidatePhoneOtpState { + google.protobuf.StringValue refresh_token = 1; + string phone = 2; + google.protobuf.Int32Value otp_length = 3; + google.protobuf.BoolValue sms_sent = 4; +} + +message EmailMarketing { + google.protobuf.BoolValue show_marketing_opt_in = 2; + google.protobuf.BoolValue show_strict_opt_in = 3; + google.protobuf.BoolValue checked_by_default = 4; +} + +message GetEmailState { + google.protobuf.StringValue refresh_token = 1; + EmailMarketing email_marketing = 2; +} + +message ValidateEmailOtpState { + google.protobuf.StringValue refresh_token = 1; + google.protobuf.Int32Value otp_length = 4; + google.protobuf.BoolValue email_sent = 5; + EmailMarketing email_marketing = 6; + + oneof email { + string unmasked_email = 2; + string masked_email = 3; + } +} + +message OnboardingState { + string refresh_token = 1; + string onboarding_token = 2; + google.protobuf.StringValue user_id = 3; +} + +message LoginResult { + string refresh_token = 1; + string auth_token = 2; + + Captcha captcha = 3; + enum Captcha { + CAPTCHA_INVALID = 0; + CAPTCHA_V1 = 1; + CAPTCHA_V2 = 2; + } + + string user_id = 4; + google.protobuf.Int64Value auth_token_ttl = 5; +} + +message AppleAccountNotFound { + bool will_link = 1; + google.protobuf.StringValue refresh_token = 2; +} + +message SocialConnection { + Service service = 1; + enum Service { + SERVICE_INVALID = 0; + SERVICE_FACEBOOK = 1; + SERVICE_GOOGLE = 2; + SERVICE_APPLE = 3; + } +} + +message SocialConnectionList { + google.protobuf.StringValue refresh_token = 1; + repeated SocialConnection connections = 2; +} + +message ValidateEmailMagicLinkOtpState { + +} + +message AuthGatewayResponse { + MetaProto meta = 1; + ErrorProto error = 2; + + oneof data { + GetPhoneState get_phone_state = 3; + ValidatePhoneOtpState validate_phone_otp_state = 4; + GetEmailState get_email_state = 5; + ValidateEmailOtpState validate_email_otp_state = 6; + OnboardingState onboarding_state = 7; + LoginResult login_result = 8; + SocialConnectionList social_connection_list = 9; + AppleAccountNotFound apple_account_not_found = 10; + ValidateEmailMagicLinkOtpState validate_email_magic_link_otp_state = 11; + } +} + +message FacebookToken { + string external_token = 1; + google.protobuf.StringValue refresh_token = 2; +} + +message Phone { + string phone = 1; + google.protobuf.StringValue refresh_token = 2; + + oneof check { + google.protobuf.StringValue captcha_token = 3; + google.protobuf.StringValue ios_device_token = 4; + google.protobuf.StringValue android_jws = 5; + } +} + +message PhoneOtpResend { + google.protobuf.StringValue phone = 1; + google.protobuf.StringValue refresh_token = 2; + + oneof check { + google.protobuf.StringValue ios_device_token = 3; + google.protobuf.StringValue android_jws = 4; + } +} + +message PhoneOtp { + google.protobuf.StringValue phone = 1; + string otp = 2; + google.protobuf.StringValue refresh_token = 3; +} + +message Email { + string email = 1; + google.protobuf.StringValue refresh_token = 2; + google.protobuf.BoolValue marketing_opt_in = 3; +} + +message EmailOtpResend { + google.protobuf.StringValue email = 1; + google.protobuf.StringValue refresh_token = 2; +} + +message GoogleToken { + string external_token = 1; + google.protobuf.StringValue refresh_token = 2; + google.protobuf.BoolValue marketing_opt_in = 3; + google.protobuf.BoolValue user_behavior = 4; +} + +message EmailOtp { + google.protobuf.StringValue email = 1; + string otp = 2; + google.protobuf.StringValue refresh_token = 3; +} + +message AppleToken { + string external_token = 1; + google.protobuf.StringValue refresh_token = 2; + google.protobuf.StringValue raw_nonce = 3; +} + +message GetInitialState { + google.protobuf.StringValue refresh_token = 1; +} + +message RefreshAuth { + string refresh_token = 1; +} + +message DismissSocialConnectionList { + string refresh_token = 1; +} + +message EmailMagicLink { + string email = 1; +} + +message EmailMagicLinkOtp { + string otp_token = 1; +} + +message AuthGatewayRequest { + oneof factor { + Phone phone = 1; + PhoneOtp phone_otp = 2; + Email email = 3; + GoogleToken google_token = 4; + EmailOtp email_otp = 5; + FacebookToken facebook_token = 6; + PhoneOtpResend phone_otp_resend = 7; + EmailOtpResend email_otp_resend = 8; + GetInitialState get_initial_state = 9; + RefreshAuth refresh_auth = 10; + AppleToken apple_token = 11; + DismissSocialConnectionList dismiss_social_connection_list = 12; + EmailMagicLink email_magic_link = 13; + EmailMagicLinkOtp email_magic_link_otp = 14; + } +} + +message Verification { + string type = 1; + string state = 2; +} + +message UnderageBan { + google.protobuf.Int64Value underage_ttl_duration_ms = 1; + google.protobuf.StringValue underage_token = 2; + Verification verification = 3; +} + +message BanAppeal { + string challenge_type = 1; + string challenge_token = 2; + string refresh_token = 3; +} + +message BanReason { + oneof reason { + UnderageBan underage_ban = 1; + BanAppeal ban_appeal = 2; + } +} +message ErrorProto { + int32 code = 1; + string message = 2; + BanReason ban_reason = 3; +} diff --git a/authgateway.py b/authgateway.py new file mode 100644 index 0000000..6b5d102 --- /dev/null +++ b/authgateway.py @@ -0,0 +1,339 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# sources: authgateway.proto +# plugin: python-betterproto +from dataclasses import dataclass +from datetime import datetime +from typing import List, Optional + +import betterproto + + +class LoginResultCaptcha(betterproto.Enum): + CAPTCHA_INVALID = 0 + CAPTCHA_V1 = 1 + CAPTCHA_V2 = 2 + + +class SocialConnectionService(betterproto.Enum): + SERVICE_INVALID = 0 + SERVICE_FACEBOOK = 1 + SERVICE_GOOGLE = 2 + SERVICE_APPLE = 3 + + +@dataclass +class MetaProto(betterproto.Message): + upstream_time: datetime = betterproto.message_field(1) + start_time: datetime = betterproto.message_field(2) + + +@dataclass +class GetPhoneState(betterproto.Message): + refresh_token: Optional[str] = betterproto.message_field( + 1, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class ValidatePhoneOtpState(betterproto.Message): + refresh_token: Optional[str] = betterproto.message_field( + 1, wraps=betterproto.TYPE_STRING + ) + phone: str = betterproto.string_field(2) + otp_length: Optional[int] = betterproto.message_field( + 3, wraps=betterproto.TYPE_INT32 + ) + sms_sent: Optional[bool] = betterproto.message_field(4, wraps=betterproto.TYPE_BOOL) + + +@dataclass +class EmailMarketing(betterproto.Message): + show_marketing_opt_in: Optional[bool] = betterproto.message_field( + 2, wraps=betterproto.TYPE_BOOL + ) + show_strict_opt_in: Optional[bool] = betterproto.message_field( + 3, wraps=betterproto.TYPE_BOOL + ) + checked_by_default: Optional[bool] = betterproto.message_field( + 4, wraps=betterproto.TYPE_BOOL + ) + + +@dataclass +class GetEmailState(betterproto.Message): + refresh_token: Optional[str] = betterproto.message_field( + 1, wraps=betterproto.TYPE_STRING + ) + email_marketing: "EmailMarketing" = betterproto.message_field(2) + + +@dataclass +class ValidateEmailOtpState(betterproto.Message): + refresh_token: Optional[str] = betterproto.message_field( + 1, wraps=betterproto.TYPE_STRING + ) + otp_length: Optional[int] = betterproto.message_field( + 4, wraps=betterproto.TYPE_INT32 + ) + email_sent: Optional[bool] = betterproto.message_field( + 5, wraps=betterproto.TYPE_BOOL + ) + email_marketing: "EmailMarketing" = betterproto.message_field(6) + unmasked_email: str = betterproto.string_field(2, group="email") + masked_email: str = betterproto.string_field(3, group="email") + + +@dataclass +class OnboardingState(betterproto.Message): + refresh_token: str = betterproto.string_field(1) + onboarding_token: str = betterproto.string_field(2) + user_id: Optional[str] = betterproto.message_field(3, wraps=betterproto.TYPE_STRING) + + +@dataclass +class LoginResult(betterproto.Message): + refresh_token: str = betterproto.string_field(1) + auth_token: str = betterproto.string_field(2) + captcha: "LoginResultCaptcha" = betterproto.enum_field(3) + user_id: str = betterproto.string_field(4) + auth_token_ttl: Optional[int] = betterproto.message_field( + 5, wraps=betterproto.TYPE_INT64 + ) + + +@dataclass +class AppleAccountNotFound(betterproto.Message): + will_link: bool = betterproto.bool_field(1) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class SocialConnection(betterproto.Message): + service: "SocialConnectionService" = betterproto.enum_field(1) + + +@dataclass +class SocialConnectionList(betterproto.Message): + refresh_token: Optional[str] = betterproto.message_field( + 1, wraps=betterproto.TYPE_STRING + ) + connections: List["SocialConnection"] = betterproto.message_field(2) + + +@dataclass +class ValidateEmailMagicLinkOtpState(betterproto.Message): + pass + + +@dataclass +class AuthGatewayResponse(betterproto.Message): + meta: "MetaProto" = betterproto.message_field(1) + error: "ErrorProto" = betterproto.message_field(2) + get_phone_state: "GetPhoneState" = betterproto.message_field(3, group="data") + validate_phone_otp_state: "ValidatePhoneOtpState" = betterproto.message_field( + 4, group="data" + ) + get_email_state: "GetEmailState" = betterproto.message_field(5, group="data") + validate_email_otp_state: "ValidateEmailOtpState" = betterproto.message_field( + 6, group="data" + ) + onboarding_state: "OnboardingState" = betterproto.message_field(7, group="data") + login_result: "LoginResult" = betterproto.message_field(8, group="data") + social_connection_list: "SocialConnectionList" = betterproto.message_field( + 9, group="data" + ) + apple_account_not_found: "AppleAccountNotFound" = betterproto.message_field( + 10, group="data" + ) + validate_email_magic_link_otp_state: "ValidateEmailMagicLinkOtpState" = betterproto.message_field( + 11, group="data" + ) + + +@dataclass +class FacebookToken(betterproto.Message): + external_token: str = betterproto.string_field(1) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class Phone(betterproto.Message): + phone: str = betterproto.string_field(1) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + captcha_token: Optional[str] = betterproto.message_field( + 3, group="check", wraps=betterproto.TYPE_STRING + ) + ios_device_token: Optional[str] = betterproto.message_field( + 4, group="check", wraps=betterproto.TYPE_STRING + ) + android_jws: Optional[str] = betterproto.message_field( + 5, group="check", wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class PhoneOtpResend(betterproto.Message): + phone: Optional[str] = betterproto.message_field(1, wraps=betterproto.TYPE_STRING) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + ios_device_token: Optional[str] = betterproto.message_field( + 3, group="check", wraps=betterproto.TYPE_STRING + ) + android_jws: Optional[str] = betterproto.message_field( + 4, group="check", wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class PhoneOtp(betterproto.Message): + phone: Optional[str] = betterproto.message_field(1, wraps=betterproto.TYPE_STRING) + otp: str = betterproto.string_field(2) + refresh_token: Optional[str] = betterproto.message_field( + 3, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class Email(betterproto.Message): + email: str = betterproto.string_field(1) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + marketing_opt_in: Optional[bool] = betterproto.message_field( + 3, wraps=betterproto.TYPE_BOOL + ) + + +@dataclass +class EmailOtpResend(betterproto.Message): + email: Optional[str] = betterproto.message_field(1, wraps=betterproto.TYPE_STRING) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class GoogleToken(betterproto.Message): + external_token: str = betterproto.string_field(1) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + marketing_opt_in: Optional[bool] = betterproto.message_field( + 3, wraps=betterproto.TYPE_BOOL + ) + user_behavior: Optional[bool] = betterproto.message_field( + 4, wraps=betterproto.TYPE_BOOL + ) + + +@dataclass +class EmailOtp(betterproto.Message): + email: Optional[str] = betterproto.message_field(1, wraps=betterproto.TYPE_STRING) + otp: str = betterproto.string_field(2) + refresh_token: Optional[str] = betterproto.message_field( + 3, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class AppleToken(betterproto.Message): + external_token: str = betterproto.string_field(1) + refresh_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + raw_nonce: Optional[str] = betterproto.message_field( + 3, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class GetInitialState(betterproto.Message): + refresh_token: Optional[str] = betterproto.message_field( + 1, wraps=betterproto.TYPE_STRING + ) + + +@dataclass +class RefreshAuth(betterproto.Message): + refresh_token: str = betterproto.string_field(1) + + +@dataclass +class DismissSocialConnectionList(betterproto.Message): + refresh_token: str = betterproto.string_field(1) + + +@dataclass +class EmailMagicLink(betterproto.Message): + email: str = betterproto.string_field(1) + + +@dataclass +class EmailMagicLinkOtp(betterproto.Message): + otp_token: str = betterproto.string_field(1) + + +@dataclass +class AuthGatewayRequest(betterproto.Message): + phone: "Phone" = betterproto.message_field(1, group="factor") + phone_otp: "PhoneOtp" = betterproto.message_field(2, group="factor") + email: "Email" = betterproto.message_field(3, group="factor") + google_token: "GoogleToken" = betterproto.message_field(4, group="factor") + email_otp: "EmailOtp" = betterproto.message_field(5, group="factor") + facebook_token: "FacebookToken" = betterproto.message_field(6, group="factor") + phone_otp_resend: "PhoneOtpResend" = betterproto.message_field(7, group="factor") + email_otp_resend: "EmailOtpResend" = betterproto.message_field(8, group="factor") + get_initial_state: "GetInitialState" = betterproto.message_field(9, group="factor") + refresh_auth: "RefreshAuth" = betterproto.message_field(10, group="factor") + apple_token: "AppleToken" = betterproto.message_field(11, group="factor") + dismiss_social_connection_list: "DismissSocialConnectionList" = betterproto.message_field( + 12, group="factor" + ) + email_magic_link: "EmailMagicLink" = betterproto.message_field(13, group="factor") + email_magic_link_otp: "EmailMagicLinkOtp" = betterproto.message_field( + 14, group="factor" + ) + + +@dataclass +class Verification(betterproto.Message): + type: str = betterproto.string_field(1) + state: str = betterproto.string_field(2) + + +@dataclass +class UnderageBan(betterproto.Message): + underage_ttl_duration_ms: Optional[int] = betterproto.message_field( + 1, wraps=betterproto.TYPE_INT64 + ) + underage_token: Optional[str] = betterproto.message_field( + 2, wraps=betterproto.TYPE_STRING + ) + verification: "Verification" = betterproto.message_field(3) + + +@dataclass +class BanAppeal(betterproto.Message): + challenge_type: str = betterproto.string_field(1) + challenge_token: str = betterproto.string_field(2) + refresh_token: str = betterproto.string_field(3) + + +@dataclass +class BanReason(betterproto.Message): + underage_ban: "UnderageBan" = betterproto.message_field(1, group="reason") + ban_appeal: "BanAppeal" = betterproto.message_field(2, group="reason") + + +@dataclass +class ErrorProto(betterproto.Message): + code: int = betterproto.int32_field(1) + message: str = betterproto.string_field(2) + ban_reason: "BanReason" = betterproto.message_field(3) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e76d2ea --- /dev/null +++ b/requirements.txt @@ -0,0 +1,18 @@ +beautifulsoup4==4.9.1 +betterproto==1.2.5 +certifi==2020.6.20 +chardet==3.0.4 +grpclib==0.4.0 +h2==3.2.0 +hpack==3.0.0 +hyperframe==5.2.0 +idna==2.10 +lxml==4.5.2 +multidict==4.7.6 +requests==2.24.0 +robobrowser==0.5.3 +six==1.15.0 +soupsieve==2.0.1 +stringcase==1.2.0 +urllib3==1.25.10 +Werkzeug==1.0.1 diff --git a/sms_auth_v3.py b/sms_auth_v3.py new file mode 100644 index 0000000..ccdef68 --- /dev/null +++ b/sms_auth_v3.py @@ -0,0 +1,133 @@ +import requests +import random +import string +import uuid +from authgateway import * +import secrets +from pathlib import Path +import sys + + +class SMSAuthException(BaseException): + pass + + +class TinderSMSAuth(object): + + def __init__(self, email=None): + self.installid = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=11)) + self.session = requests.Session() + self.session.headers.update({"user-agent": "Tinder Android Version 11.24.0"}) + self.url = "https://api.gotinder.com" + self.funnelid = str(uuid.uuid4()) + self.appsessionid = str(uuid.uuid4()) + self.deviceid = secrets.token_hex(8) + self.authtoken = None + self.refreshtoken = None + self.userid = None + self.email = email + self.phonenumber = None + if Path("smstoken.txt").exists(): + print("smstoken.txt found, if you wish to auth again from scratch, delete smstoken.txt") + with open("smstoken.txt", "r") as fh: + tokens = fh.read() + t = tokens.split(",") + self.authtoken = t[0] + self.refreshtoken = t[1] + print("authToken found: " + self.authtoken) + self.login() + + def _postloginreq(self, body, headers=None): + if headers is not None: + self.session.headers.update(headers) + r = self.session.post(self.url + "/v3/auth/login", data=bytes(body)) + response = AuthGatewayResponse().parse(r.content).to_dict() + return response + + def loginwrapper(self, body, seconds, headers=None): + response = self._postloginreq(body, headers) + print(response) + if "validatePhoneOtpState" in response.keys() and response["validatePhoneOtpState"]["smsSent"]: + otpresponse = input("OTP Response from SMS: ") + resp = PhoneOtp(phone=self.phonenumber, otp=otpresponse) + messageresponse = AuthGatewayRequest(phone_otp=resp) + seconds += random.uniform(30, 90) + header_timer = {"app-session-time-elapsed": format(seconds, ".3f")} + return self.loginwrapper(messageresponse, seconds, header_timer) + elif "getPhoneState" in response.keys(): + self.refreshtoken = response['getPhoneState']['refreshToken'] + messageresponse = AuthGatewayRequest(refresh_auth=RefreshAuth(refresh_token=self.refreshtoken)) + seconds += random.uniform(30, 90) + header_timer = {"app-session-time-elapsed": format(seconds, ".3f")} + return self.loginwrapper(messageresponse, seconds, header_timer) + elif "validateEmailOtpState" in response.keys() and response["validateEmailOtpState"]["emailSent"]: + emailoptresponse = input("Check your email and input the verification code just sent to you: ") + refreshtoken = response["validateEmailOtpState"]["refreshToken"] + if self.email is None: + self.email = input("Input your email: ") + messageresponse = AuthGatewayRequest(email_otp=EmailOtp(otp=emailoptresponse, email=self.email, refresh_token=refreshtoken)) + seconds += random.uniform(30, 90) + header_timer = {"app-session-time-elapsed": format(seconds, ".3f")} + return self.loginwrapper(messageresponse, seconds, header_timer) + elif "getEmailState" in response.keys(): + refreshtoken = response['getEmailState']['refreshToken'] + if self.email is None: + self.email = input("Input your email: ") + seconds += random.uniform(30, 90) + header_timer = {"app-session-time-elapsed": format(seconds, ".3f")} + messageresponse = AuthGatewayRequest(email=Email(email=self.email, refresh_token=refreshtoken)) + return self.loginwrapper(messageresponse, seconds, header_timer) + elif "error" in response.keys() and response["error"]["message"] == 'INVALID_REFRESH_TOKEN': + print("Refresh token error, restarting auth") + phonenumber = input("phone number (starting with 1, numbers only): ") + self.phonenumber = phonenumber + messageresponse = AuthGatewayRequest(phone=Phone(phone=self.phonenumber)) + seconds += random.uniform(30, 90) + header_timer = {"app-session-time-elapsed": format(seconds, ".3f")} + return self.loginwrapper(messageresponse, seconds, header_timer) + elif "loginResult" in response.keys() and "authToken" in response["loginResult"].keys(): + return response + else: + raise SMSAuthException + + def login(self): + payload = { + "device_id": self.installid, + "experiments": ["default_login_token", "tinder_u_verification_method", "tinder_rules", + "user_interests_available"] + } + self.session.post(self.url + "/v2/buckets", json=payload) + if self.refreshtoken is not None: + print("Attempting to refresh auth token with saved refresh token") + messageout = AuthGatewayRequest(get_initial_state=GetInitialState(refresh_token=self.refreshtoken)) + else: + phonenumber = input("phone number (starting with 1, numbers only): ") + self.phonenumber = phonenumber + messageout = AuthGatewayRequest(phone=Phone(phone=self.phonenumber)) + seconds = random.uniform(100, 250) + headers = { + 'tinder-version': "12.6.0", 'install-id': self.installid, + 'user-agent': "Tinder Android Version 12.6.0", 'connection': "close", + 'platform-variant': "Google-Play", 'persistent-device-id': self.deviceid, + 'accept-encoding': "gzip, deflate", 'appsflyer-id': "1600144077225-7971032049730563486", + 'platform': "android", 'app-version': "4023", 'os-version': "25", 'app-session-id': self.appsessionid, + 'x-supported-image-formats': "webp", 'funnel-session-id': self.funnelid, + 'app-session-time-elapsed': format(seconds, ".3f"), 'accept-language': "en-US", + 'content-type': "application/x-protobuf" + } + response = self.loginwrapper(messageout, seconds, headers) + self.refreshtoken = response["loginResult"]["refreshToken"] + self.authtoken = response["loginResult"]["authToken"] + self.session.headers.update({"X-AUTH-TOKEN": self.authtoken}) + with open("smstoken.txt", "w") as fh: + fh.write(self.authtoken + "," + self.refreshtoken) + print("Auth token saved to smstoken.txt") + + +if __name__ == '__main__': + print("This script will use the sms login to obtain the auth token, which will be saved to smstoken.txt") + if len(sys.argv) > 1: + emailaddy = sys.argv[1] + else: + emailaddy = None + TinderSMSAuth(email=emailaddy) \ No newline at end of file