################################################################################# # This file is part of Mana Launcher. # Copyright (C) 2021 Jesusalva # # Distributed under the MIT license, except for Steam parts. ################################################################################# # This is for Vault accounts default uedit = {"mail": "", "pasd": "", "totp": "", "rbmx": ifte(persistent.email is None, False, True), "rbpd": ifte(persistent.passd is None, False, True)} init python: def ueditor_input(key, temp="", tp="str"): #temp=renpy.input("Please insert new value for this variable.\nCurrent value: [variable]") global uedit variable="" # Convert input if needed # tp int → convert to int # tp key → Replace the key # tp bool → Toogles the value if tp == "int": try: variable=int(temp) except: renpy.notify("Invalid numeric input") variable=0 # Sorry, but gets bad otherwise else: try: variable=str(temp) except: renpy.notify("Invalid string input") # Save input uedit[key] = variable return class UEditorInputValue(InputValue): # inpu: str or int def __init__(self, key, placeholder="", inpu="str"): global uedit self.key = key self.variable = uedit[key] or str(placeholder) self.inpu = inpu self.default=True self.editable=True # Conditional hacks if (persistent.email is not None and self.variable == "a@a.com"): self.variable = str(persistent.email) uedit[key] = str(self.variable) if (persistent.passd is not None and self.variable == "***"): if LEGACY: self.variable = str(bytearray((x ^ int(persistent.rhash/mp.sub) for x in bytearray(persistent.passd, 'utf-8')))) else: self.variable = bytearray((x ^ int(persistent.rhash/mp.sub) for x in persistent.passd)).decode('utf-8') uedit[key] = str(self.variable) def get_text(self): try: return str(self.variable) except: traceback.print_exc() return "" #return globals()[self.variable] def set_text(self, s): #globals()[self.variable] = s ueditor_input(self.key, s, self.inpu) def enter(self): renpy.restart_interaction() #renpy.run(self.Disable()) #raise renpy.IgnoreEvent() screen register_vault(): ## Ensure other screens do not get input while this screen is displayed. modal True zorder 200 style_prefix "confirm" add "gui/overlay/confirm.png" frame: vbox: xalign .5 yalign .5 spacing 30 label _("Welcome to the {b}Mana Launcher{/b}!\n\nIf you do not have an account, one will be created for you."): style "confirm_prompt" xalign 0.5 null height 24 hbox: spacing 10 label _("Email: ") $ input=Input( value=UEditorInputValue("mail", "a@a.com", "str"), copypaste=True, allow="qwertyuiopasdfghjklçzxcvbnm QWERTYUIOPASDFGHJKLÇZXCVBNM1234567890-+=!(),.:;@_", length=52) button: #key_events True action input.enable add input hbox: spacing 10 label _("Password: ") # For some reason, we don't accept all ascii special codes # WARNING: Non-ascii will break the hashing. $ input=Input( value=UEditorInputValue("pasd", "***", "str"), copypaste=True, allow="qwertyuiopasdfghjklçzxcvbnm QWERTYUIOPASDFGHJKLÇZXCVBNM1234567890-+=!(),.:;@*^_", length=52, mask=ifte(persistent.maskpass, "*", None)) button: #key_events True action input.enable add input showif persistent.totp is None: hbox: spacing 10 label _("TOTP: ") $ input=Input( value=UEditorInputValue("totp", "000000", "str"), copypaste=True, allow="1234567890", length=6) button: #key_events True action input.enable add input # FIXME: Checkboxes # * Remember me # * Disable 2FA/TOTP null height 24 button: #xmaximum 32 #ymaximum 32 hbox: spacing 10 if (uedit["rbmx"]): add "gui/button/check_1.png" else: add "gui/button/check_0.png" null width 5 text _("Remember email") size 18 action [SetDict(uedit, "rbmx", not uedit["rbmx"]), Function(renpy.restart_interaction)] button: #xmaximum 32 #ymaximum 32 hbox: spacing 10 if (uedit["rbpd"]): add "gui/button/check_1.png" else: add "gui/button/check_0.png" null width 5 text _("Remember password (unsafe!)") size 18 action [SetDict(uedit, "rbpd", not uedit["rbpd"]), Function(renpy.restart_interaction)] hbox: xalign 0.5 spacing 100 textbutton _("OK"): action ifte(len(uedit["pasd"]) >= 4, Return(), None) keysym ['K_KP_ENTER', 'K_RETURN'] label register_vault: call screen register_vault() $ status_update(pc=92) if persistent.totp is not None: python: uedit["totp"] = calcOTP(base64.b32decode(persistent.totp.encode('utf-8'), True)) $ email = uedit["mail"] $ password = uedit["pasd"] $ code2FA = uedit["totp"] $ status_update(pc=95) $ data = {"mail": email, "pass": password, "totp": code2FA[:6] } $ r = vault.post(VAULT_HOST+"/user_auth", json=data) # We save the variables on the meanwhile if uedit["rbmx"]: $ persistent.email = str(email) if uedit["rbpd"]: $ hsh = renpy.random.randint(11, 127) $ mp.sub = renpy.random.randint(127, 16777215) $ persistent.rhash = int(hsh)*mp.sub if LEGACY: $ persistent.passd = str(bytearray(x ^ int(hsh) for x in bytearray(password, 'utf-8'))) else: $ persistent.passd = bytearray(ord(x) ^ int(hsh) for x in password) $ mp.save() # Wait for Vault to confirm. if (r.status_code != 200): if (r.status_code not in [401, 403]): call screen notice(_("Vault returned error %d\n\nPlease try again later." % r.status_code)) else: call screen notice(_("Vault returned error %d (incorrect login/password)\n\nPlease try again later." % r.status_code)) return # Check if we have success python: try: status_update(pc=98) stdout("Vault result: (%d) %s" % (r.status_code, ifte(config.developer, r.text, "OK"))) auth2 = r.json() vaultId = auth2["vaultId"] vaultToken = auth2["token"] vaultOTP = auth2["otp"] except: traceback.print_exc() stdout("Error - Vault result is bad.") # Maybe we got a message informing this is a new account? try: if (auth2["status"] == 1): status_update("Creating account and logging in...") renpy.notify("Account created! Check email.") time.sleep(1.0) # Attempt to save the TOTP credential (DISCOURAGED) if persistent.autologin and "totp" in auth2.keys(): persistent.totp = auth2["totp"].split("secret=")[1].split("&")[0] except: pass ############ ## Cleanup $ del data $ del code2FA $ del email $ del method if vaultId: $ status_update(_("Success!"), 100) else: $ status_update(_("{color=#F00}Failure!{/color}"), pc=100) return