def cmd_authenticator_status(args): account = args.account.lower().strip() secrets_file = UserDataFile('authenticator/{}.json'.format(account)) sa = None wa = BetterMWA(account) if secrets_file.exists(): sa = SteamAuthenticator(secrets_file.read_json(), backend=wa) try: wa.bcli_login(sa_instance=sa) except (KeyboardInterrupt, EOFError): print("Login interrupted") return 1 # error if sa is None: sa = SteamAuthenticator(backend=wa) status = sa.status() print("----- Status ------------") mode = status['steamguard_scheme'] if mode == 0: print("Steam Guard mode: disabled/insecure") elif mode == 1: print("Steam Guard mode: enabled (email)") elif mode == 2: print("Steam Guard mode: enabled (authenticator)") else: print("Steam Guard mode: unknown ({})".format(mode)) print("Authenticator enabled:", "Yes" if status['state'] == 1 else "No") print("Authenticator allowed:", "Yes" if status['state'] else "No") print("Email verified:", "Yes" if status['email_validated'] else "No") print("External allowed:", "Yes" if status['allow_external_authenticator'] else "No") if status['state'] == 1: print("----- Token details -----") print("Token GID:", status['token_gid']) print("Created at:", fmt_datetime(status['time_created'])) print("Device identifier:", status['device_identifier']) print("Classified agent:", status['classified_agent']) print("Revocation attempts remaining:", status['revocation_attempts_remaining'])
class clientLoginWindow(Toplevel): #Initialize def __init__(self, parent, colorDic, conn, rootClassRef): #Declare class variables self.authWindow = None self.colorDic = colorDic self.conn = conn self.parent = parent self.rootClassRef = rootClassRef #Initialize window's frame Toplevel.__init__(self) #Window title self.windowTitle = Label(self, text="New Account") self.windowTitle.configure(font=("Segoe UI", 12), bg=self.colorDic["windowTitleBackground"], fg=self.colorDic["windowTitleForeground"], width="350", pady=10) self.windowTitle.pack() #Steam logo image self.img = ImageTk.PhotoImage(file="images/gui/steam_logo.png") self.steamLogo = Label(self, bg=self.colorDic["appBackground"], image=self.img) self.steamLogo.pack(anchor="w", padx=35, pady=25) #Login item's frame self.loginHolder = Frame(self, bg=self.colorDic["appBackground"]) self.loginHolder.pack(anchor="w", padx=45, pady=25) self.labelHolder = Frame(self.loginHolder, bg=self.colorDic["appBackground"]) self.labelHolder.pack(side="left") self.entryHolder = Frame(self.loginHolder, bg=self.colorDic["appBackground"]) self.entryHolder.pack(side="left") #Account name and password text self.userNameLabel = Label(self.labelHolder, text="Account Name", bg=self.colorDic["appBackground"], fg=self.colorDic["infoLabelForeground"], font=("Segoe UI", 12)) self.userNameLabel.pack(padx=5, pady=5, anchor="e") self.passwordLabel = Label(self.labelHolder, text="Password", bg=self.colorDic["appBackground"], fg=self.colorDic["infoLabelForeground"], font=("Segoe UI", 12)) self.passwordLabel.pack(padx=5, pady=5, anchor="e") #Account name and password entry boxes self.userNameEntry = Entry(self.entryHolder, width=45) self.userNameEntry.pack(padx=5, pady=5) self.userNameEntry.focus() self.passwordEntry = Entry(self.entryHolder, width=45, show="*") self.passwordEntry.pack(padx=5, pady=5) #Button holding frame, login button and cancel button self.buttonHolder = Frame(self, bg=self.colorDic["appBackground"]) self.buttonHolder.pack(pady=15) self.loginButton = Button(self.buttonHolder, text="Login to Steam", font=("Segoe UI", 12), relief="flat", cursor="hand2", command=self.login_account) self.loginButton.configure(fg=self.colorDic["actionButtonForeground"], bg=self.colorDic["actionButtonBackground"]) self.loginButton.pack(padx=30, ipady=10, ipadx=10, side="left") self.cancelButton = Button(self.buttonHolder, text="Cancel", font=("Segoe UI", 12), relief="flat", cursor="hand2", command=self.destroy) self.cancelButton.configure(fg=self.colorDic["cancelButtonForeground"], bg=self.colorDic["cancelButtonBackground"]) self.cancelButton.pack(padx=30, ipady=10, ipadx=10, side="left") #Login and add guard method def login_account(self): #Login to steam with provided credentials self.userObject = clientData(self.userNameEntry.get(), self.passwordEntry.get(), None, None) self.userObject.login() #If password is invalid if self.userObject.loginResult == EResult.InvalidPassword: #Show error stating password is incorrect self.rootClassRef.show_message( None, "error", "Your password is incorrect. Please try again.") else: #If email code is required if self.userObject.loginResult in (EResult.AccountLogonDenied, EResult.InvalidLoginAuthCode): self.authWindow = promptFor2FA(self.parent, self.colorDic, True, self.rootClassRef) #If 2FA code is required elif self.userObject.loginResult in ( EResult.AccountLoginDeniedNeedTwoFactor, EResult.TwoFactorCodeMismatch): self.authWindow = promptFor2FA(self.parent, self.colorDic, False, self.rootClassRef) #If email or 2FA code was required if self.authWindow: #Start 2FA prompt window self.authWindow.geometry("400x250") self.authWindow.resizable(0, 0) self.authWindow.configure(bg=self.colorDic["appBackground"]) guiController(self.authWindow).center() self.authWindow.wait_window() #If auth code was set if self.authWindow.guardCode: #If auth code was sent to email if self.authWindow.isEmail: self.userObject = clientData(self.userNameEntry.get(), self.passwordEntry.get(), self.authWindow.guardCode, None) else: #If auth code was sent to mobile self.userObject = clientData(self.userNameEntry.get(), self.passwordEntry.get(), None, self.authWindow.guardCode) self.userObject.login() #If login and code is correct if self.userObject.loginResult == EResult.OK: self.steamGuardController = SteamAuthenticator( medium=self.userObject.client) if self.steamGuardController.status( )['steamguard_scheme'] != 2: #If account has a phone number if self.steamGuardController.has_phone_number(): #Add steam guard self.steamGuardController.add() #Start 2FA prompt window to get phone confirmation self.authWindow = promptFor2FA(self.parent, self.colorDic, False, self.rootClassRef) self.authWindow.geometry("400x250") self.authWindow.resizable(0, 0) self.authWindow.configure( bg=self.colorDic["appBackground"]) guiController(self.authWindow).center() self.authWindow.title("Steam Guardian - Mobile") self.authWindow.windowTitle.configure( text="Enter Text Sent to Phone") self.authWindow.wait_window() #If phone code is set if self.authWindow.guardCode: try: self.steamGuardController.finalize( self.authWindow.guardCode) except: #If phone code is incorrect show an error self.rootClassRef.show_message( None, "error", "Couldn't confirm your phone. Code is incorrect!" ) else: #Update data and gui self.conn.create_user( str( json.dumps(self.steamGuardController. secrets)), str(self.userObject.client.user.steam_id), self.userNameEntry.get(), self.passwordEntry.get()) self.rootClassRef.update_guard() #We destroy our window here because Steam loves to rate limit if you retry too fast self.destroy() else: #If account doesn't have phone number show an error self.rootClassRef.show_message( None, "error", "Your account is missing a phone number to confirm.\nPlease add one and try again!" ) webbrowser.open( "https://store.steampowered.com/phone/manage") else: #If account already has 2FA (email is fine) show an error self.rootClassRef.show_message( None, "error", "Your account already has Steam Guard Mobile.\nPlease disable it and try again." ) else: #If steam guard code was incorrect. self.rootClassRef.show_message(None, "error", "Login or code was incorrect.")
def cmd_authenticator_add(args): account = args.account.lower().strip() secrets_file = UserDataFile('authenticator/{}.json'.format(account)) sa = None if secrets_file.exists(): if not args.force: print( "There is already an authenticator for that account. Use --force to overwrite" ) return 1 # error sa = SteamAuthenticator(secrets_file.read_json()) print("To add an authenticator, first we need to login to Steam") print("Account name:", account) wa = BetterMWA(account) try: wa.bcli_login(sa_instance=sa) except (KeyboardInterrupt, EOFError): print("Login interrupted") return 1 # error print("Login successful. Checking pre-conditions...") sa = SteamAuthenticator(backend=wa) status = sa.status() _LOG.debug("Authenticator status: %s", status) if not status['email_validated']: print("Account needs a verified email address") return 1 # error if status['state'] == 1: print("This account already has an authenticator.") print("You need to remove it first, before proceeding") return 1 # error if not status['authenticator_allowed']: print("This account is now allowed to have authenticator") return 1 # error # check phone number, and add one if its missing if not sa.has_phone_number(): print("No phone number on this account. This is required.") if pmt_confirmation("Do you want to add a phone number?", default_yes=True): print("Phone number need to include country code and no spaces.") while True: phnum = pmt_input("Enter phone number:", regex=r'^(\+|00)[0-9]+$') resp = sa.validate_phone_number(phnum) _LOG.debug("Phone number validation for %r: %s", phnum, resp) if not resp.get('is_valid', False): print("That number is not valid for Steam.") continue if not sa.add_phone_number(phnum): print("Failed to add phone number!") continue print("Phone number added. Confirmation SMS sent.") while not sa.confirm_phone_number( pmt_input("Enter SMS code:", regex='^[0-9]+$')): print("Code was incorrect. Try again.") break else: # user declined adding a phone number, we cant proceed return 1 # error # being adding authenticator setup sa.add() _LOG.debug("Authenticator secrets obtained. Saving to disk") secrets_file.write_json(sa.secrets) # Setup Steam app in conjuction if pmt_confirmation("Do you want to use Steam app too?", default_yes=False): print("Great! Go and setup Steam Guard in your app.") print("Once completed, generate a code and enter it below.") showed_fail_info = False fail_counter = 0 while True: code = pmt_input( "Steam Guard code:", regex='^[23456789BCDFGHJKMNPQRTVWXYbcdfghjkmnpqrtvwxy]{5}$') # code match if sa.get_code() == code.upper(): break # success # code do not match else: fail_counter += 1 if fail_counter >= 3 and not showed_fail_info: showed_fail_info = True print("The codes do not match. This can be caused by:") print("* The code was not entered correctly") print("* Your system time is not synchronized") print("* Steam has made changes to their backend") if not pmt_confirmation("Code mismatch. Try again?", default_yes=True): _LOG.debug("Removing secrets file") secrets_file.remove() return 1 # failed, exit # only setup steamctl 2fa else: print( "Authenticator secrets obtained. SMS code for finalization sent.") while True: code = pmt_input("Enter SMS code:", regex='^[0-9]+$') try: sa.finalize(code) except SteamAuthenticatorError as exp: print("Finalization error: %s", exp) continue else: break # finish line print("Authenticator added successfully!") print("Get a code: {} authenticator code {}".format(__appname__, account)) print("Or QR code: {} authenticator qrcode {}".format( __appname__, account))