From 71f79ba87eb9d8c628a8d71dbf9cde8dbdd1a899 Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Sat, 30 Jul 2022 12:38:43 +0800 Subject: [PATCH 1/9] Update support Add: Microsoft Account Support Add: Login status persistence (Microsoft account) --- minecraft/authentication.py | 242 ++++++++++++++++++++++++++++++++++++ start.py | 45 +++++-- 2 files changed, 274 insertions(+), 13 deletions(-) diff --git a/minecraft/authentication.py b/minecraft/authentication.py index e0135fd4..9b860155 100644 --- a/minecraft/authentication.py +++ b/minecraft/authentication.py @@ -1,6 +1,7 @@ import requests import json import uuid +import os from .exceptions import YggdrasilError #: The base url for Ygdrassil requests @@ -264,6 +265,247 @@ def join(self, server_id): _raise_from_response(res) return True +class Microsoft_AuthenticationToken(object): + """ + Represents an authentication token. + + See https://wiki.vg/Microsoft_Authentication_Scheme. + """ + + + UserLoginURL = "https://login.live.com/oauth20_authorize.srf?client_id=00000000402b5328&response_type=code\ +&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf" + oauth20_URL = 'https://login.live.com/oauth20_token.srf' + XBL_URL = 'https://user.auth.xboxlive.com/user/authenticate' + XSTS_URL = 'https://xsts.auth.xboxlive.com/xsts/authorize' + LOGIN_WITH_XBOX_URL = 'https://api.minecraftservices.com/authentication/login_with_xbox' + CheckAccount_URL = 'https://api.minecraftservices.com/entitlements/mcstore' + Profile_URL = 'https://api.minecraftservices.com/minecraft/profile' + + jwt_Token='' + + def __init__(self, access_token=None): + self.access_token = access_token + self.profile = Profile() + + def GetoAuth20(self, code: str='') -> object: + if code == '': + print("Please copy this link to your browser to open: \n%s" % self.UserLoginURL) + code = input("After logging in, paste the 'code' field in your browser's address bar here:") + oauth20 = requests.post(self.oauth20_URL, data={ + "client_id":"00000000402b5328", + "code":f"{code}", + "grant_type":"authorization_code", + "redirect_uri":"https://login.live.com/oauth20_desktop.srf", + "scope":"service::user.auth.xboxlive.com::MBI_SSL" + }, + headers={"content-type": "application/x-www-form-urlencoded"}, + timeout=15 + ) + oauth20 = json.loads(oauth20.text) + if 'error' in oauth20: + print("Error: %s" % oauth20["error"]) + return 1 + else: + self.oauth20_access_token=oauth20['access_token'] + self.oauth20_refresh_token=oauth20['refresh_token'] + oauth20_access_token=oauth20['access_token'] + oauth20_refresh_token=oauth20['refresh_token'] + return {"access_token":oauth20_access_token,"refresh_token":oauth20_refresh_token} + + def GetXBL(self, access_token: str) -> object: + XBL = requests.post(self.XBL_URL, + json={"Properties": {"AuthMethod": "RPS","SiteName": "user.auth.xboxlive.com","RpsTicket": f"{access_token}"}, + "RelyingParty": "http://auth.xboxlive.com","TokenType": "JWT"}, + headers=HEADERS, timeout=15 + ) + return { + "Token": json.loads(XBL.text)['Token'], + "uhs": json.loads(XBL.text)['DisplayClaims']['xui'][0]['uhs'] + } + + def GetXSTS(self, access_token: str) -> object: + XBL = requests.post(self.XSTS_URL, + json={ + "Properties": {"SandboxId": "RETAIL","UserTokens": [f"{access_token}"]}, + "RelyingParty": "rp://api.minecraftservices.com/","TokenType": "JWT" + }, + headers=HEADERS, timeout=15 + ) + return { + "Token": json.loads(XBL.text)['Token'], + "uhs": json.loads(XBL.text)['DisplayClaims']['xui'][0]['uhs'] + } + + def GetXBOX(self, access_token: str,uhs: str) -> str: + mat_jwt = requests.post(self.LOGIN_WITH_XBOX_URL, json={"identityToken": f"XBL3.0 x={uhs};{access_token}"}, + headers=HEADERS, timeout=15) + self.access_token = json.loads(mat_jwt.text)['access_token'] + return self.access_token + + def CheckAccount(self, jwt_Token: str) -> bool: + CheckAccount = requests.get(self.CheckAccount_URL, headers={"Authorization": f"Bearer {jwt_Token}"}, + timeout=15) + CheckAccount = len(json.loads(CheckAccount.text)['items']) + if CheckAccount != 0: + return True + else: + return False + + def GetProfile(self, access_token: str) -> object: + if self.CheckAccount(access_token): + Profile = requests.get(self.Profile_URL, headers={"Authorization": f"Bearer {access_token}"}, + timeout=15) + Profile = json.loads(Profile.text) + if 'error' in Profile: + return False + self.profile.id_ = Profile["id"] + self.profile.name = Profile["name"] + self.username = Profile["name"] + return True + else: + return False + + @property + def authenticated(self): + """ + Attribute which is ``True`` when the token is authenticated and + ``False`` when it isn't. + """ + if not self.username: + return False + + if not self.access_token: + return False + + if not self.oauth20_refresh_token: + return False + + if not self.profile: + return False + + return True + + def authenticate(self): + "Get verification information for a Microsoft account" + oauth20 = self.GetoAuth20() + XBL = self.GetXBL(oauth20['access_token']) + XSTS = self.GetXSTS(XBL['Token']) + XBOX = self.GetXBOX(XSTS['Token'],XSTS['uhs']) + if self.GetProfile(XBOX): + print(f'GameID: {self.profile.id_}') + self.PersistenceLogoin_w() + return True + else: + print('Account does not exist') + return False + + def refresh(self): + """ + Refreshes the `AuthenticationToken`. Used to keep a user logged in + between sessions and is preferred over storing a user's password in a + file. + + Returns: + Returns `True` if `AuthenticationToken` was successfully refreshed. + Otherwise it raises an exception. + + Raises: + minecraft.exceptions.YggdrasilError + ValueError - if `AuthenticationToken.access_token` or + `AuthenticationToken.client_token` isn't set. + """ + if self.access_token is None: + raise ValueError("'access_token' not set!'") + + if self.oauth20_refresh_token is None: + raise ValueError("'oauth20_refresh_token' is not set!") + + oauth20 = requests.post(self.oauth20_URL,data={ + "client_id":"00000000402b5328", + "refresh_token":f"{self.oauth20_refresh_token}", + "grant_type":"refresh_token", + "redirect_uri":"https://login.live.com/oauth20_desktop.srf", + "scope":"service::user.auth.xboxlive.com::MBI_SSL" + }, + headers={"content-type": "application/x-www-form-urlencoded"}, + timeout=15 + ) + oauth20 = json.loads(oauth20.text) + if 'error' in oauth20: + print("Error: %s" % oauth20["error"]) + return False + else: + self.oauth20_access_token=oauth20['access_token'] + self.oauth20_refresh_token=oauth20['refresh_token'] + XBL = self.GetXBL(self.oauth20_access_token) + XSTS = self.GetXSTS(XBL['Token']) + XBOX = self.GetXBOX(XSTS['Token'],XSTS['uhs']) + if self.GetProfile(XBOX): + print(f'账户: {self.profile.id_}') + return True + else: + print('账户不存在') + return False + + def join(self, server_id): + """ + Informs the Mojang session-server that we're joining the + MineCraft server with id ``server_id``. + + Parameters: + server_id - ``str`` with the server id + + Returns: + ``True`` if no errors occured + + Raises: + :class:`minecraft.exceptions.YggdrasilError` + + """ + if not self.authenticated: + err = "AuthenticationToken hasn't been authenticated yet!" + raise YggdrasilError(err) + + res = _make_request(SESSION_SERVER, "join", + {"accessToken": self.access_token, + "selectedProfile": self.profile.to_dict(), + "serverId": server_id}) + + if res.status_code != 204: + _raise_from_response(res) + return True + + def PersistenceLogoin_w(self): + "Save access token persistent login" + if not self.authenticated: + err = "AuthenticationToken hasn't been authenticated yet!" + raise YggdrasilError(err) + if not os.path.exists("Persistence"): + os.mkdir("Persistence") + "Save access_token and oauth20_refresh_token" + with open(f"Persistence/{self.username}", mode='w', encoding='utf-8') as file_obj: + file_obj.write(f'{{"access_token": "{self.access_token}","oauth20_refresh_token": "{self.oauth20_refresh_token}"}}') + file_obj.close() + return True + + def PersistenceLogoin_r(self, GameID: str): + "Load access token persistent login" + if not os.path.exists("Persistence"): + return False + "Load access_token and oauth20_refresh_token" + if os.path.isfile(f"Persistence/{GameID}"): + with open(f"Persistence/{GameID}", mode='r', encoding='utf-8') as file_obj: + Persistence = file_obj.read() + file_obj.close() + Persistence = json.loads(Persistence) + self.access_token = Persistence["access_token"] + self.oauth20_refresh_token = Persistence["oauth20_refresh_token"] + self.GetProfile(self.access_token) + return self.authenticated + else: + return False + def _make_request(server, endpoint, data): """ diff --git a/start.py b/start.py index 353a1581..98c9bb4f 100755 --- a/start.py +++ b/start.py @@ -14,8 +14,12 @@ def get_options(): parser = OptionParser() + parser.add_option("-a", "--authentication-method", dest="auth", + default="microsoft", + help="what to use for authentication, allowed values are: microsoft, mojang") + parser.add_option("-u", "--username", dest="username", default=None, - help="username to log in with") + help="User name used for login, if AUTH is microsoft and a persistent archive is detected locally, the persistent login information will be read first") parser.add_option("-p", "--password", dest="password", default=None, help="password to log in with") @@ -38,13 +42,15 @@ def get_options(): (options, args) = parser.parse_args() - if not options.username: - options.username = input("Enter your username: ") + if options.auth == 'mojang': + + if not options.username: + options.username = input("Enter your username: ") - if not options.password and not options.offline: - options.password = getpass.getpass("Enter your password (leave " - "blank for offline mode): ") - options.offline = options.offline or (options.password == "") + if not options.password and not options.offline: + options.password = getpass.getpass("Enter your password (leave " + "blank for offline mode): ") + options.offline = options.offline or (options.password == "") if not options.server: options.server = input("Enter server host or host:port " @@ -68,12 +74,25 @@ def main(): connection = Connection( options.address, options.port, username=options.username) else: - auth_token = authentication.AuthenticationToken() - try: - auth_token.authenticate(options.username, options.password) - except YggdrasilError as e: - print(e) - sys.exit() + if options.auth == "mojang": + auth_token = authentication.AuthenticationToken() + try: + auth_token.authenticate(options.username, options.password) + except YggdrasilError as e: + print(e) + sys.exit() + elif options.auth == "microsoft": + auth_token = authentication.Microsoft_AuthenticationToken() + try: + if options.username: + if not auth_token.PersistenceLogoin_r(options.username): + print(f"登陆 {options.username} 失败") + else: + auth_token.authenticate() + except YggdrasilError as e: + print(e) + sys.exit() + print("Logged in as %s..." % auth_token.username) connection = Connection( options.address, options.port, auth_token=auth_token) From 131128e30c9e6dd6bc46f1c9886e11333e172e5b Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Mon, 1 Aug 2022 20:18:15 +0800 Subject: [PATCH 2/9] Fix: Can't log in after token expires --- .gitignore | 1 + minecraft/authentication.py | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b35e4795..09721355 100644 --- a/.gitignore +++ b/.gitignore @@ -86,3 +86,4 @@ sftp-config.json ### pyCraft ### credentials +Persistence/* diff --git a/minecraft/authentication.py b/minecraft/authentication.py index 9b860155..fa6ec44e 100644 --- a/minecraft/authentication.py +++ b/minecraft/authentication.py @@ -442,10 +442,11 @@ def refresh(self): XSTS = self.GetXSTS(XBL['Token']) XBOX = self.GetXBOX(XSTS['Token'],XSTS['uhs']) if self.GetProfile(XBOX): - print(f'账户: {self.profile.id_}') + self.PersistenceLogoin_w() + print(f'account: {self.profile.id_}') return True else: - print('账户不存在') + print('Account does not exist') return False def join(self, server_id): @@ -501,7 +502,7 @@ def PersistenceLogoin_r(self, GameID: str): Persistence = json.loads(Persistence) self.access_token = Persistence["access_token"] self.oauth20_refresh_token = Persistence["oauth20_refresh_token"] - self.GetProfile(self.access_token) + self.refresh() return self.authenticated else: return False From ac7ff6d85d38ff6558be7b971ef6151c86522857 Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Mon, 1 Aug 2022 23:12:38 +0800 Subject: [PATCH 3/9] Fix: Error executing in non-project directory --- minecraft/authentication.py | 19 +++++++++++++------ start.py | 6 ++++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/minecraft/authentication.py b/minecraft/authentication.py index fa6ec44e..23ff3002 100644 --- a/minecraft/authentication.py +++ b/minecraft/authentication.py @@ -389,6 +389,8 @@ def authenticated(self): def authenticate(self): "Get verification information for a Microsoft account" oauth20 = self.GetoAuth20() + if oauth20 == 1: + return False XBL = self.GetXBL(oauth20['access_token']) XSTS = self.GetXSTS(XBL['Token']) XBOX = self.GetXBOX(XSTS['Token'],XSTS['uhs']) @@ -479,24 +481,29 @@ def join(self, server_id): def PersistenceLogoin_w(self): "Save access token persistent login" + ProjectDir = os.path.dirname(os.path.dirname(f'{__file__}')) + PersistenceDir = f'{ProjectDir}/Persistence' if not self.authenticated: err = "AuthenticationToken hasn't been authenticated yet!" raise YggdrasilError(err) - if not os.path.exists("Persistence"): - os.mkdir("Persistence") + if not os.path.exists(PersistenceDir): + os.mkdir(PersistenceDir) + print(PersistenceDir) "Save access_token and oauth20_refresh_token" - with open(f"Persistence/{self.username}", mode='w', encoding='utf-8') as file_obj: + with open(f"{PersistenceDir}/{self.username}", mode='w', encoding='utf-8') as file_obj: file_obj.write(f'{{"access_token": "{self.access_token}","oauth20_refresh_token": "{self.oauth20_refresh_token}"}}') file_obj.close() return True def PersistenceLogoin_r(self, GameID: str): "Load access token persistent login" - if not os.path.exists("Persistence"): + ProjectDir = os.path.dirname(os.path.dirname(f'{__file__}')) + PersistenceDir = f'{ProjectDir}/Persistence' + if not os.path.exists(PersistenceDir): return False "Load access_token and oauth20_refresh_token" - if os.path.isfile(f"Persistence/{GameID}"): - with open(f"Persistence/{GameID}", mode='r', encoding='utf-8') as file_obj: + if os.path.isfile(f"{PersistenceDir}/{GameID}"): + with open(f"{PersistenceDir}/{GameID}", mode='r', encoding='utf-8') as file_obj: Persistence = file_obj.read() file_obj.close() Persistence = json.loads(Persistence) diff --git a/start.py b/start.py index 98c9bb4f..56daf84c 100755 --- a/start.py +++ b/start.py @@ -86,9 +86,11 @@ def main(): try: if options.username: if not auth_token.PersistenceLogoin_r(options.username): - print(f"登陆 {options.username} 失败") + print(f"Login to {options.username} failed") + sys.exit(1) else: - auth_token.authenticate() + if not auth_token.authenticate(): + sys.exit(2) except YggdrasilError as e: print(e) sys.exit() From c407bf26c4f68cbdec168b8c306fe56a08ce473d Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Tue, 30 Aug 2022 11:44:18 +0800 Subject: [PATCH 4/9] style: Code style conforms to flake8 --- minecraft/authentication.py | 140 +++++++++++++++++++++++------------- start.py | 9 ++- 2 files changed, 96 insertions(+), 53 deletions(-) diff --git a/minecraft/authentication.py b/minecraft/authentication.py index 23ff3002..a7549374 100644 --- a/minecraft/authentication.py +++ b/minecraft/authentication.py @@ -272,34 +272,40 @@ class Microsoft_AuthenticationToken(object): See https://wiki.vg/Microsoft_Authentication_Scheme. """ - - UserLoginURL = "https://login.live.com/oauth20_authorize.srf?client_id=00000000402b5328&response_type=code\ -&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf" + UserLoginURL = "https://login.live.com/oauth20_authorize.srf?\ +client_id=00000000402b5328&response_type=code\ +&scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=\ +https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf" oauth20_URL = 'https://login.live.com/oauth20_token.srf' XBL_URL = 'https://user.auth.xboxlive.com/user/authenticate' XSTS_URL = 'https://xsts.auth.xboxlive.com/xsts/authorize' - LOGIN_WITH_XBOX_URL = 'https://api.minecraftservices.com/authentication/login_with_xbox' + LOGIN_WITH_XBOX_URL = "https://api.minecraftservices.com/\ +authentication/login_with_xbox" CheckAccount_URL = 'https://api.minecraftservices.com/entitlements/mcstore' Profile_URL = 'https://api.minecraftservices.com/minecraft/profile' - - jwt_Token='' - + jwt_Token = '' def __init__(self, access_token=None): self.access_token = access_token self.profile = Profile() def GetoAuth20(self, code: str='') -> object: - if code == '': - print("Please copy this link to your browser to open: \n%s" % self.UserLoginURL) - code = input("After logging in, paste the 'code' field in your browser's address bar here:") + if code == '' : + print( + "Please copy this link to your browser to open:" + "\n%s" % self.UserLoginURL + ) + code = input( + "After logging in," + "paste the 'code' field in your browser's address bar here:" + ) oauth20 = requests.post(self.oauth20_URL, data={ - "client_id":"00000000402b5328", - "code":f"{code}", - "grant_type":"authorization_code", - "redirect_uri":"https://login.live.com/oauth20_desktop.srf", - "scope":"service::user.auth.xboxlive.com::MBI_SSL" + "client_id": "00000000402b5328", + "code": f"{code}", + "grant_type": "authorization_code", + "redirect_uri": "https://login.live.com/oauth20_desktop.srf", + "scope": "service::user.auth.xboxlive.com::MBI_SSL" }, - headers={"content-type": "application/x-www-form-urlencoded"}, + headers={"content-type": "application/x-www-form-urlencoded"}, timeout=15 ) oauth20 = json.loads(oauth20.text) @@ -307,16 +313,26 @@ def GetoAuth20(self, code: str='') -> object: print("Error: %s" % oauth20["error"]) return 1 else: - self.oauth20_access_token=oauth20['access_token'] - self.oauth20_refresh_token=oauth20['refresh_token'] - oauth20_access_token=oauth20['access_token'] - oauth20_refresh_token=oauth20['refresh_token'] - return {"access_token":oauth20_access_token,"refresh_token":oauth20_refresh_token} + self.oauth20_access_token = oauth20['access_token'] + self.oauth20_refresh_token = oauth20['refresh_token'] + oauth20_access_token = oauth20['access_token'] + oauth20_refresh_token = oauth20['refresh_token'] + return { + "access_token": oauth20_access_token, + "refresh_token": oauth20_refresh_token + } def GetXBL(self, access_token: str) -> object: - XBL = requests.post(self.XBL_URL, - json={"Properties": {"AuthMethod": "RPS","SiteName": "user.auth.xboxlive.com","RpsTicket": f"{access_token}"}, - "RelyingParty": "http://auth.xboxlive.com","TokenType": "JWT"}, + XBL = requests.post(self.XBL_URL, + json={ + "Properties": { + "AuthMethod": "RPS", + "SiteName": "user.auth.xboxlive.com", + "RpsTicket": f"{access_token}" + }, + "RelyingParty": "http://auth.xboxlive.com", + "TokenType": "JWT" + }, headers=HEADERS, timeout=15 ) return { @@ -325,27 +341,38 @@ def GetXBL(self, access_token: str) -> object: } def GetXSTS(self, access_token: str) -> object: - XBL = requests.post(self.XSTS_URL, + XBL = requests.post(self.XSTS_URL, json={ - "Properties": {"SandboxId": "RETAIL","UserTokens": [f"{access_token}"]}, - "RelyingParty": "rp://api.minecraftservices.com/","TokenType": "JWT" + "Properties": { + "SandboxId": "RETAIL", + "UserTokens": [f"{access_token}"] + }, + "RelyingParty": "rp://api.minecraftservices.com/", + "TokenType": "JWT" }, - headers=HEADERS, timeout=15 + headers=HEADERS, + timeout=15 ) return { "Token": json.loads(XBL.text)['Token'], "uhs": json.loads(XBL.text)['DisplayClaims']['xui'][0]['uhs'] } - def GetXBOX(self, access_token: str,uhs: str) -> str: - mat_jwt = requests.post(self.LOGIN_WITH_XBOX_URL, json={"identityToken": f"XBL3.0 x={uhs};{access_token}"}, - headers=HEADERS, timeout=15) + def GetXBOX(self, access_token: str, uhs: str) -> str: + mat_jwt = requests.post( + self.LOGIN_WITH_XBOX_URL, + json={"identityToken": f"XBL3.0 x={uhs};{access_token}"}, + headers=HEADERS, timeout=15 + ) self.access_token = json.loads(mat_jwt.text)['access_token'] return self.access_token - + def CheckAccount(self, jwt_Token: str) -> bool: - CheckAccount = requests.get(self.CheckAccount_URL, headers={"Authorization": f"Bearer {jwt_Token}"}, - timeout=15) + CheckAccount = requests.get( + self.CheckAccount_URL, + headers={"Authorization": f"Bearer {jwt_Token}"}, + timeout=15 + ) CheckAccount = len(json.loads(CheckAccount.text)['items']) if CheckAccount != 0: return True @@ -354,8 +381,11 @@ def CheckAccount(self, jwt_Token: str) -> bool: def GetProfile(self, access_token: str) -> object: if self.CheckAccount(access_token): - Profile = requests.get(self.Profile_URL, headers={"Authorization": f"Bearer {access_token}"}, - timeout=15) + Profile = requests.get( + self.Profile_URL, + headers={"Authorization": f"Bearer {access_token}"}, + timeout=15 + ) Profile = json.loads(Profile.text) if 'error' in Profile: return False @@ -393,7 +423,7 @@ def authenticate(self): return False XBL = self.GetXBL(oauth20['access_token']) XSTS = self.GetXSTS(XBL['Token']) - XBOX = self.GetXBOX(XSTS['Token'],XSTS['uhs']) + XBOX = self.GetXBOX(XSTS['Token'], XSTS['uhs']) if self.GetProfile(XBOX): print(f'GameID: {self.profile.id_}') self.PersistenceLogoin_w() @@ -423,12 +453,12 @@ def refresh(self): if self.oauth20_refresh_token is None: raise ValueError("'oauth20_refresh_token' is not set!") - oauth20 = requests.post(self.oauth20_URL,data={ - "client_id":"00000000402b5328", - "refresh_token":f"{self.oauth20_refresh_token}", - "grant_type":"refresh_token", - "redirect_uri":"https://login.live.com/oauth20_desktop.srf", - "scope":"service::user.auth.xboxlive.com::MBI_SSL" + oauth20 = requests.post(self.oauth20_URL, data={ + "client_id": "00000000402b5328", + "refresh_token": f"{self.oauth20_refresh_token}", + "grant_type": "refresh_token", + "redirect_uri": "https://login.live.com/oauth20_desktop.srf", + "scope": "service::user.auth.xboxlive.com::MBI_SSL" }, headers={"content-type": "application/x-www-form-urlencoded"}, timeout=15 @@ -438,11 +468,11 @@ def refresh(self): print("Error: %s" % oauth20["error"]) return False else: - self.oauth20_access_token=oauth20['access_token'] - self.oauth20_refresh_token=oauth20['refresh_token'] + self.oauth20_access_token = oauth20['access_token'] + self.oauth20_refresh_token = oauth20['refresh_token'] XBL = self.GetXBL(self.oauth20_access_token) XSTS = self.GetXSTS(XBL['Token']) - XBOX = self.GetXBOX(XSTS['Token'],XSTS['uhs']) + XBOX = self.GetXBOX(XSTS['Token'], XSTS['uhs']) if self.GetProfile(XBOX): self.PersistenceLogoin_w() print(f'account: {self.profile.id_}') @@ -490,8 +520,14 @@ def PersistenceLogoin_w(self): os.mkdir(PersistenceDir) print(PersistenceDir) "Save access_token and oauth20_refresh_token" - with open(f"{PersistenceDir}/{self.username}", mode='w', encoding='utf-8') as file_obj: - file_obj.write(f'{{"access_token": "{self.access_token}","oauth20_refresh_token": "{self.oauth20_refresh_token}"}}') + with open( + f"{PersistenceDir}/{self.username}", + mode='w', + encoding='utf-8' + ) as file_obj: + file_obj.write( + f'{{"access_token": "{self.access_token}","oauth20_refresh_token": "{self.oauth20_refresh_token}"}}' + ) file_obj.close() return True @@ -503,12 +539,16 @@ def PersistenceLogoin_r(self, GameID: str): return False "Load access_token and oauth20_refresh_token" if os.path.isfile(f"{PersistenceDir}/{GameID}"): - with open(f"{PersistenceDir}/{GameID}", mode='r', encoding='utf-8') as file_obj: + with open( + f"{PersistenceDir}/{GameID}", mode='r', encoding='utf-8' + ) as file_obj: Persistence = file_obj.read() file_obj.close() Persistence = json.loads(Persistence) self.access_token = Persistence["access_token"] - self.oauth20_refresh_token = Persistence["oauth20_refresh_token"] + self.oauth20_refresh_token = Persistence[ + "oauth20_refresh_token" + ] self.refresh() return self.authenticated else: diff --git a/start.py b/start.py index 56daf84c..f96f59d1 100755 --- a/start.py +++ b/start.py @@ -16,10 +16,13 @@ def get_options(): parser.add_option("-a", "--authentication-method", dest="auth", default="microsoft", - help="what to use for authentication, allowed values are: microsoft, mojang") + help="what to use for authentication, " + "allowed values are: microsoft, mojang") parser.add_option("-u", "--username", dest="username", default=None, - help="User name used for login, if AUTH is microsoft and a persistent archive is detected locally, the persistent login information will be read first") + help="User name used for login, " + "if AUTH is microsoft and a persistent archive is detected locally, " + "the persistent login information will be read first") parser.add_option("-p", "--password", dest="password", default=None, help="password to log in with") @@ -94,7 +97,7 @@ def main(): except YggdrasilError as e: print(e) sys.exit() - + print("Logged in as %s..." % auth_token.username) connection = Connection( options.address, options.port, auth_token=auth_token) From 36393239a5057971f128bf4f28ae576d7e4ca8e5 Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Tue, 30 Aug 2022 12:17:36 +0800 Subject: [PATCH 5/9] Stop using the f-string feature in favor of python 3.5 Fix new issue in last commit to pass flake8 (bug = me^2 XD) --- minecraft/authentication.py | 82 ++++++++++++++++++++++--------------- start.py | 5 ++- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/minecraft/authentication.py b/minecraft/authentication.py index a7549374..cc26a6cd 100644 --- a/minecraft/authentication.py +++ b/minecraft/authentication.py @@ -265,6 +265,7 @@ def join(self, server_id): _raise_from_response(res) return True + class Microsoft_AuthenticationToken(object): """ Represents an authentication token. @@ -283,29 +284,31 @@ class Microsoft_AuthenticationToken(object): authentication/login_with_xbox" CheckAccount_URL = 'https://api.minecraftservices.com/entitlements/mcstore' Profile_URL = 'https://api.minecraftservices.com/minecraft/profile' + jwt_Token = '' - def __init__(self, access_token=None): + + def __init__(self, access_token = None): self.access_token = access_token self.profile = Profile() - + def GetoAuth20(self, code: str='') -> object: - if code == '' : + if code == '': print( "Please copy this link to your browser to open:" "\n%s" % self.UserLoginURL ) - code = input( + code = input( "After logging in," - "paste the 'code' field in your browser's address bar here:" + "paste the 'code' field in your browser's address bar here:" ) oauth20 = requests.post(self.oauth20_URL, data={ - "client_id": "00000000402b5328", - "code": f"{code}", - "grant_type": "authorization_code", - "redirect_uri": "https://login.live.com/oauth20_desktop.srf", + "client_id": "00000000402b5328", + "code": "{}".format(code), + "grant_type": "authorization_code", + "redirect_uri": "https://login.live.com/oauth20_desktop.srf", "scope": "service::user.auth.xboxlive.com::MBI_SSL" }, - headers={"content-type": "application/x-www-form-urlencoded"}, + headers={"content-type": "application/x-www-form-urlencoded"}, timeout=15 ) oauth20 = json.loads(oauth20.text) @@ -324,16 +327,18 @@ def GetoAuth20(self, code: str='') -> object: def GetXBL(self, access_token: str) -> object: XBL = requests.post(self.XBL_URL, - json={ + json = + { "Properties": { "AuthMethod": "RPS", "SiteName": "user.auth.xboxlive.com", - "RpsTicket": f"{access_token}" + "RpsTicket": "{}".format(access_token) }, "RelyingParty": "http://auth.xboxlive.com", "TokenType": "JWT" }, - headers=HEADERS, timeout=15 + headers = HEADERS, + timeout = 15 ) return { "Token": json.loads(XBL.text)['Token'], @@ -342,16 +347,17 @@ def GetXBL(self, access_token: str) -> object: def GetXSTS(self, access_token: str) -> object: XBL = requests.post(self.XSTS_URL, - json={ + json = + { "Properties": { "SandboxId": "RETAIL", - "UserTokens": [f"{access_token}"] + "UserTokens": ["{}".format(access_token)] }, "RelyingParty": "rp://api.minecraftservices.com/", "TokenType": "JWT" }, - headers=HEADERS, - timeout=15 + headers = HEADERS, + timeout = 15 ) return { "Token": json.loads(XBL.text)['Token'], @@ -361,7 +367,10 @@ def GetXSTS(self, access_token: str) -> object: def GetXBOX(self, access_token: str, uhs: str) -> str: mat_jwt = requests.post( self.LOGIN_WITH_XBOX_URL, - json={"identityToken": f"XBL3.0 x={uhs};{access_token}"}, + json= + { + "identityToken": "XBL3.0 x={};{}".format(uhs, access_token) + }, headers=HEADERS, timeout=15 ) self.access_token = json.loads(mat_jwt.text)['access_token'] @@ -370,7 +379,7 @@ def GetXBOX(self, access_token: str, uhs: str) -> str: def CheckAccount(self, jwt_Token: str) -> bool: CheckAccount = requests.get( self.CheckAccount_URL, - headers={"Authorization": f"Bearer {jwt_Token}"}, + headers={"Authorization": "Bearer {}".format(jwt_Token)}, timeout=15 ) CheckAccount = len(json.loads(CheckAccount.text)['items']) @@ -383,7 +392,7 @@ def GetProfile(self, access_token: str) -> object: if self.CheckAccount(access_token): Profile = requests.get( self.Profile_URL, - headers={"Authorization": f"Bearer {access_token}"}, + headers={"Authorization": "Bearer {}".format(access_token)}, timeout=15 ) Profile = json.loads(Profile.text) @@ -425,7 +434,7 @@ def authenticate(self): XSTS = self.GetXSTS(XBL['Token']) XBOX = self.GetXBOX(XSTS['Token'], XSTS['uhs']) if self.GetProfile(XBOX): - print(f'GameID: {self.profile.id_}') + print('GameID: {}'.format(self.profile.id_)) self.PersistenceLogoin_w() return True else: @@ -455,7 +464,7 @@ def refresh(self): oauth20 = requests.post(self.oauth20_URL, data={ "client_id": "00000000402b5328", - "refresh_token": f"{self.oauth20_refresh_token}", + "refresh_token": "{}".format(self.oauth20_refresh_token), "grant_type": "refresh_token", "redirect_uri": "https://login.live.com/oauth20_desktop.srf", "scope": "service::user.auth.xboxlive.com::MBI_SSL" @@ -475,7 +484,7 @@ def refresh(self): XBOX = self.GetXBOX(XSTS['Token'], XSTS['uhs']) if self.GetProfile(XBOX): self.PersistenceLogoin_w() - print(f'account: {self.profile.id_}') + print('account: {}'.format(self.profile.id_)) return True else: print('Account does not exist') @@ -511,8 +520,8 @@ def join(self, server_id): def PersistenceLogoin_w(self): "Save access token persistent login" - ProjectDir = os.path.dirname(os.path.dirname(f'{__file__}')) - PersistenceDir = f'{ProjectDir}/Persistence' + ProjectDir = os.path.dirname(os.path.dirname('{}'.format(__file__))) + PersistenceDir = '{}/Persistence'.format(ProjectDir) if not self.authenticated: err = "AuthenticationToken hasn't been authenticated yet!" raise YggdrasilError(err) @@ -521,26 +530,31 @@ def PersistenceLogoin_w(self): print(PersistenceDir) "Save access_token and oauth20_refresh_token" with open( - f"{PersistenceDir}/{self.username}", + "{}/{}".format(PersistenceDir,self.username), mode='w', encoding='utf-8' ) as file_obj: - file_obj.write( - f'{{"access_token": "{self.access_token}","oauth20_refresh_token": "{self.oauth20_refresh_token}"}}' - ) - file_obj.close() + file_obj.write( + '{{"access_token": "{}","oauth20_refresh_token": "{}"}}'. + format( + self.access_token, + self.oauth20_refresh_token + ) + ) + file_obj.close() return True def PersistenceLogoin_r(self, GameID: str): "Load access token persistent login" - ProjectDir = os.path.dirname(os.path.dirname(f'{__file__}')) - PersistenceDir = f'{ProjectDir}/Persistence' + ProjectDir = os.path.dirname(os.path.dirname('{}'.format(__file__))) + PersistenceDir = '{}/Persistence'.format(ProjectDir) if not os.path.exists(PersistenceDir): return False "Load access_token and oauth20_refresh_token" - if os.path.isfile(f"{PersistenceDir}/{GameID}"): + if os.path.isfile("{}/{}".format(PersistenceDir, GameID)): with open( - f"{PersistenceDir}/{GameID}", mode='r', encoding='utf-8' + "{}/{}".format(PersistenceDir, GameID), + mode='r', encoding='utf-8' ) as file_obj: Persistence = file_obj.read() file_obj.close() diff --git a/start.py b/start.py index f96f59d1..faacc02d 100755 --- a/start.py +++ b/start.py @@ -21,8 +21,9 @@ def get_options(): parser.add_option("-u", "--username", dest="username", default=None, help="User name used for login, " - "if AUTH is microsoft and a persistent archive is detected locally, " - "the persistent login information will be read first") + "if AUTH is microsoft and a persistent archive " + "is detected locally, the persistent login " + "information will be read first") parser.add_option("-p", "--password", dest="password", default=None, help="password to log in with") From 12c00b9cd6a21cafff36c1dbce7ecd65a2008e18 Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Tue, 30 Aug 2022 12:43:07 +0800 Subject: [PATCH 6/9] Trying to pass flake8 I think it's a bit weird to write this way (bug = me^2 XD) --- minecraft/authentication.py | 65 +++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/minecraft/authentication.py b/minecraft/authentication.py index cc26a6cd..8f95bcc1 100644 --- a/minecraft/authentication.py +++ b/minecraft/authentication.py @@ -287,11 +287,11 @@ class Microsoft_AuthenticationToken(object): jwt_Token = '' - def __init__(self, access_token = None): + def __init__(self, access_token=None): self.access_token = access_token self.profile = Profile() - def GetoAuth20(self, code: str='') -> object: + def GetoAuth20(self, code='') -> object: if code == '': print( "Please copy this link to your browser to open:" @@ -327,18 +327,18 @@ def GetoAuth20(self, code: str='') -> object: def GetXBL(self, access_token: str) -> object: XBL = requests.post(self.XBL_URL, - json = - { - "Properties": { - "AuthMethod": "RPS", - "SiteName": "user.auth.xboxlive.com", - "RpsTicket": "{}".format(access_token) + json= + { + "Properties": { + "AuthMethod": "RPS", + "SiteName": "user.auth.xboxlive.com", + "RpsTicket": "{}".format(access_token) + }, + "RelyingParty": "http://auth.xboxlive.com", + "TokenType": "JWT" }, - "RelyingParty": "http://auth.xboxlive.com", - "TokenType": "JWT" - }, - headers = HEADERS, - timeout = 15 + headers=HEADERS, + timeout=15 ) return { "Token": json.loads(XBL.text)['Token'], @@ -347,17 +347,17 @@ def GetXBL(self, access_token: str) -> object: def GetXSTS(self, access_token: str) -> object: XBL = requests.post(self.XSTS_URL, - json = - { - "Properties": { - "SandboxId": "RETAIL", - "UserTokens": ["{}".format(access_token)] + json= + { + "Properties": { + "SandboxId": "RETAIL", + "UserTokens": ["{}".format(access_token)] + }, + "RelyingParty": "rp://api.minecraftservices.com/", + "TokenType": "JWT" }, - "RelyingParty": "rp://api.minecraftservices.com/", - "TokenType": "JWT" - }, - headers = HEADERS, - timeout = 15 + headers=HEADERS, + timeout=15 ) return { "Token": json.loads(XBL.text)['Token'], @@ -368,9 +368,9 @@ def GetXBOX(self, access_token: str, uhs: str) -> str: mat_jwt = requests.post( self.LOGIN_WITH_XBOX_URL, json= - { - "identityToken": "XBL3.0 x={};{}".format(uhs, access_token) - }, + { + "identityToken": "XBL3.0 x={};{}".format(uhs, access_token) + }, headers=HEADERS, timeout=15 ) self.access_token = json.loads(mat_jwt.text)['access_token'] @@ -530,16 +530,17 @@ def PersistenceLogoin_w(self): print(PersistenceDir) "Save access_token and oauth20_refresh_token" with open( - "{}/{}".format(PersistenceDir,self.username), + "{}/{}".format(PersistenceDir, self.username), mode='w', encoding='utf-8' ) as file_obj: file_obj.write( - '{{"access_token": "{}","oauth20_refresh_token": "{}"}}'. - format( - self.access_token, - self.oauth20_refresh_token - ) + '{{"{}": "{}","{}": "{}"}}'.format( + 'access_token', + self.access_token, + 'oauth20_refresh_token', + self.oauth20_refresh_token + ) ) file_obj.close() return True From 7a04aa387a527000559421efaeb809f056b0fd00 Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Tue, 30 Aug 2022 12:57:21 +0800 Subject: [PATCH 7/9] try to pass flake8 --- minecraft/authentication.py | 182 +++++++++++++++++------------------- 1 file changed, 88 insertions(+), 94 deletions(-) diff --git a/minecraft/authentication.py b/minecraft/authentication.py index 8f95bcc1..5485e33a 100644 --- a/minecraft/authentication.py +++ b/minecraft/authentication.py @@ -17,6 +17,7 @@ class Profile(object): Container class for a MineCraft Selected profile. See: ``_ """ + def __init__(self, id_=None, name=None): self.id_ = id_ self.name = name @@ -26,8 +27,7 @@ def to_dict(self): Returns ``self`` in dictionary-form, which can be serialized by json. """ if self: - return {"id": self.id_, - "name": self.name} + return {"id": self.id_, "name": self.name} else: raise AttributeError("Profile is not yet populated.") @@ -155,9 +155,10 @@ def refresh(self): if self.client_token is None: raise ValueError("'client_token' is not set!") - res = _make_request(AUTH_SERVER, - "refresh", {"accessToken": self.access_token, - "clientToken": self.client_token}) + res = _make_request(AUTH_SERVER, "refresh", { + "accessToken": self.access_token, + "clientToken": self.client_token + }) _raise_from_response(res) @@ -212,8 +213,10 @@ def sign_out(username, password): Raises: minecraft.exceptions.YggdrasilError """ - res = _make_request(AUTH_SERVER, "signout", - {"username": username, "password": password}) + res = _make_request(AUTH_SERVER, "signout", { + "username": username, + "password": password + }) if _raise_from_response(res) is None: return True @@ -229,9 +232,10 @@ def invalidate(self): Raises: :class:`minecraft.exceptions.YggdrasilError` """ - res = _make_request(AUTH_SERVER, "invalidate", - {"accessToken": self.access_token, - "clientToken": self.client_token}) + res = _make_request(AUTH_SERVER, "invalidate", { + "accessToken": self.access_token, + "clientToken": self.client_token + }) if res.status_code != 204: _raise_from_response(res) @@ -256,10 +260,12 @@ def join(self, server_id): err = "AuthenticationToken hasn't been authenticated yet!" raise YggdrasilError(err) - res = _make_request(SESSION_SERVER, "join", - {"accessToken": self.access_token, - "selectedProfile": self.profile.to_dict(), - "serverId": server_id}) + res = _make_request( + SESSION_SERVER, "join", { + "accessToken": self.access_token, + "selectedProfile": self.profile.to_dict(), + "serverId": server_id + }) if res.status_code != 204: _raise_from_response(res) @@ -277,11 +283,13 @@ class Microsoft_AuthenticationToken(object): client_id=00000000402b5328&response_type=code\ &scope=service%3A%3Auser.auth.xboxlive.com%3A%3AMBI_SSL&redirect_uri=\ https%3A%2F%2Flogin.live.com%2Foauth20_desktop.srf" + oauth20_URL = 'https://login.live.com/oauth20_token.srf' XBL_URL = 'https://user.auth.xboxlive.com/user/authenticate' XSTS_URL = 'https://xsts.auth.xboxlive.com/xsts/authorize' LOGIN_WITH_XBOX_URL = "https://api.minecraftservices.com/\ authentication/login_with_xbox" + CheckAccount_URL = 'https://api.minecraftservices.com/entitlements/mcstore' Profile_URL = 'https://api.minecraftservices.com/minecraft/profile' @@ -293,15 +301,14 @@ def __init__(self, access_token=None): def GetoAuth20(self, code='') -> object: if code == '': - print( - "Please copy this link to your browser to open:" - "\n%s" % self.UserLoginURL - ) + print("Please copy this link to your browser to open:" + "\n%s" % self.UserLoginURL) code = input( "After logging in," - "paste the 'code' field in your browser's address bar here:" - ) - oauth20 = requests.post(self.oauth20_URL, data={ + "paste the 'code' field in your browser's address bar here:") + oauth20 = requests.post( + self.oauth20_URL, + data={ "client_id": "00000000402b5328", "code": "{}".format(code), "grant_type": "authorization_code", @@ -309,8 +316,7 @@ def GetoAuth20(self, code='') -> object: "scope": "service::user.auth.xboxlive.com::MBI_SSL" }, headers={"content-type": "application/x-www-form-urlencoded"}, - timeout=15 - ) + timeout=15) oauth20 = json.loads(oauth20.text) if 'error' in oauth20: print("Error: %s" % oauth20["error"]) @@ -327,19 +333,17 @@ def GetoAuth20(self, code='') -> object: def GetXBL(self, access_token: str) -> object: XBL = requests.post(self.XBL_URL, - json= - { - "Properties": { - "AuthMethod": "RPS", - "SiteName": "user.auth.xboxlive.com", - "RpsTicket": "{}".format(access_token) - }, - "RelyingParty": "http://auth.xboxlive.com", - "TokenType": "JWT" - }, - headers=HEADERS, - timeout=15 - ) + json={ + "Properties": { + "AuthMethod": "RPS", + "SiteName": "user.auth.xboxlive.com", + "RpsTicket": "{}".format(access_token) + }, + "RelyingParty": "http://auth.xboxlive.com", + "TokenType": "JWT" + }, + headers=HEADERS, + timeout=15) return { "Token": json.loads(XBL.text)['Token'], "uhs": json.loads(XBL.text)['DisplayClaims']['xui'][0]['uhs'] @@ -347,18 +351,17 @@ def GetXBL(self, access_token: str) -> object: def GetXSTS(self, access_token: str) -> object: XBL = requests.post(self.XSTS_URL, - json= - { - "Properties": { - "SandboxId": "RETAIL", - "UserTokens": ["{}".format(access_token)] - }, - "RelyingParty": "rp://api.minecraftservices.com/", - "TokenType": "JWT" - }, - headers=HEADERS, - timeout=15 - ) + json={ + "Properties": { + "SandboxId": "RETAIL", + "UserTokens": ["{}".format(access_token)] + }, + "RelyingParty": + "rp://api.minecraftservices.com/", + "TokenType": "JWT" + }, + headers=HEADERS, + timeout=15) return { "Token": json.loads(XBL.text)['Token'], "uhs": json.loads(XBL.text)['DisplayClaims']['xui'][0]['uhs'] @@ -367,12 +370,9 @@ def GetXSTS(self, access_token: str) -> object: def GetXBOX(self, access_token: str, uhs: str) -> str: mat_jwt = requests.post( self.LOGIN_WITH_XBOX_URL, - json= - { - "identityToken": "XBL3.0 x={};{}".format(uhs, access_token) - }, - headers=HEADERS, timeout=15 - ) + json={"identityToken": "XBL3.0 x={};{}".format(uhs, access_token)}, + headers=HEADERS, + timeout=15) self.access_token = json.loads(mat_jwt.text)['access_token'] return self.access_token @@ -380,8 +380,7 @@ def CheckAccount(self, jwt_Token: str) -> bool: CheckAccount = requests.get( self.CheckAccount_URL, headers={"Authorization": "Bearer {}".format(jwt_Token)}, - timeout=15 - ) + timeout=15) CheckAccount = len(json.loads(CheckAccount.text)['items']) if CheckAccount != 0: return True @@ -393,8 +392,7 @@ def GetProfile(self, access_token: str) -> object: Profile = requests.get( self.Profile_URL, headers={"Authorization": "Bearer {}".format(access_token)}, - timeout=15 - ) + timeout=15) Profile = json.loads(Profile.text) if 'error' in Profile: return False @@ -462,16 +460,17 @@ def refresh(self): if self.oauth20_refresh_token is None: raise ValueError("'oauth20_refresh_token' is not set!") - oauth20 = requests.post(self.oauth20_URL, data={ - "client_id": "00000000402b5328", - "refresh_token": "{}".format(self.oauth20_refresh_token), - "grant_type": "refresh_token", - "redirect_uri": "https://login.live.com/oauth20_desktop.srf", - "scope": "service::user.auth.xboxlive.com::MBI_SSL" + oauth20 = requests.post( + self.oauth20_URL, + data={ + "client_id": "00000000402b5328", + "refresh_token": "{}".format(self.oauth20_refresh_token), + "grant_type": "refresh_token", + "redirect_uri": "https://login.live.com/oauth20_desktop.srf", + "scope": "service::user.auth.xboxlive.com::MBI_SSL" }, headers={"content-type": "application/x-www-form-urlencoded"}, - timeout=15 - ) + timeout=15) oauth20 = json.loads(oauth20.text) if 'error' in oauth20: print("Error: %s" % oauth20["error"]) @@ -509,10 +508,12 @@ def join(self, server_id): err = "AuthenticationToken hasn't been authenticated yet!" raise YggdrasilError(err) - res = _make_request(SESSION_SERVER, "join", - {"accessToken": self.access_token, - "selectedProfile": self.profile.to_dict(), - "serverId": server_id}) + res = _make_request( + SESSION_SERVER, "join", { + "accessToken": self.access_token, + "selectedProfile": self.profile.to_dict(), + "serverId": server_id + }) if res.status_code != 204: _raise_from_response(res) @@ -529,20 +530,13 @@ def PersistenceLogoin_w(self): os.mkdir(PersistenceDir) print(PersistenceDir) "Save access_token and oauth20_refresh_token" - with open( - "{}/{}".format(PersistenceDir, self.username), - mode='w', - encoding='utf-8' - ) as file_obj: - file_obj.write( - '{{"{}": "{}","{}": "{}"}}'.format( - 'access_token', - self.access_token, - 'oauth20_refresh_token', - self.oauth20_refresh_token - ) - ) - file_obj.close() + with open("{}/{}".format(PersistenceDir, self.username), + mode='w', + encoding='utf-8') as file_obj: + file_obj.write('{{"{}": "{}","{}": "{}"}}'.format( + 'access_token', self.access_token, 'oauth20_refresh_token', + self.oauth20_refresh_token)) + file_obj.close() return True def PersistenceLogoin_r(self, GameID: str): @@ -553,17 +547,15 @@ def PersistenceLogoin_r(self, GameID: str): return False "Load access_token and oauth20_refresh_token" if os.path.isfile("{}/{}".format(PersistenceDir, GameID)): - with open( - "{}/{}".format(PersistenceDir, GameID), - mode='r', encoding='utf-8' - ) as file_obj: + with open("{}/{}".format(PersistenceDir, GameID), + mode='r', + encoding='utf-8') as file_obj: Persistence = file_obj.read() file_obj.close() Persistence = json.loads(Persistence) self.access_token = Persistence["access_token"] self.oauth20_refresh_token = Persistence[ - "oauth20_refresh_token" - ] + "oauth20_refresh_token"] self.refresh() return self.authenticated else: @@ -582,8 +574,10 @@ def _make_request(server, endpoint, data): Returns: A `requests.Request` object. """ - res = requests.post(server + "/" + endpoint, data=json.dumps(data), - headers=HEADERS, timeout=15) + res = requests.post(server + "/" + endpoint, + data=json.dumps(data), + headers=HEADERS, + timeout=15) return res @@ -606,13 +600,13 @@ def _raise_from_response(res): message = "[{status_code}] Malformed error message: '{response_text}'" message = message.format(status_code=str(res.status_code), response_text=res.text) - exception.args = (message,) + exception.args = (message, ) else: message = "[{status_code}] {error}: '{error_message}'" message = message.format(status_code=str(res.status_code), error=json_resp["error"], error_message=json_resp["errorMessage"]) - exception.args = (message,) + exception.args = (message, ) exception.yggdrasil_error = json_resp["error"] exception.yggdrasil_message = json_resp["errorMessage"] exception.yggdrasil_cause = json_resp.get("cause") From 498ee69ea0b009643a2f131f1f4af46b16a13186 Mon Sep 17 00:00:00 2001 From: MemoryShadow Date: Wed, 2 Nov 2022 21:31:55 +0800 Subject: [PATCH 8/9] Fix: Python 3.5 Error prompted --- start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.py b/start.py index faacc02d..0e1e88a7 100755 --- a/start.py +++ b/start.py @@ -90,7 +90,7 @@ def main(): try: if options.username: if not auth_token.PersistenceLogoin_r(options.username): - print(f"Login to {options.username} failed") + print("Login to {} failed".format(options.username)) sys.exit(1) else: if not auth_token.authenticate(): From fb0a2d17f1d95d12cb86acdaebd42f03f5639cab Mon Sep 17 00:00:00 2001 From: MemoryShadow <31596045+MemoryShadow@users.noreply.github.com> Date: Sun, 4 Feb 2024 02:10:33 +0000 Subject: [PATCH 9/9] revert(start): Restore the default login behavior to mojang account --- start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/start.py b/start.py index 0e1e88a7..38a01e27 100755 --- a/start.py +++ b/start.py @@ -15,7 +15,7 @@ def get_options(): parser = OptionParser() parser.add_option("-a", "--authentication-method", dest="auth", - default="microsoft", + default="mojang", help="what to use for authentication, " "allowed values are: microsoft, mojang")