diff --git a/callofduty/auth.py b/callofduty/auth.py index eb58caa..ce0a8ec 100644 --- a/callofduty/auth.py +++ b/callofduty/auth.py @@ -6,7 +6,7 @@ from .client import Client from .errors import LoginFailure -from .http import HTTP +from .http import HTTP, JSONorText log: logging.Logger = logging.getLogger(__name__) @@ -17,10 +17,12 @@ class Auth: Parameters ---------- - email : str + email : str, optional Activision account email address. - password : str + password : str, optional Activision account password. + sso : str, optional + Activision single sign-on cookie value. """ loginUrl: str = "https://profile.callofduty.com/cod/mapp/login" @@ -29,12 +31,21 @@ class Auth: _accessToken: Optional[str] = None _deviceId: Optional[str] = None - def __init__(self, email: str, password: str): - self.email: str = email - self.password: str = password - + def __init__( + self, + email: Optional[str] = None, + password: Optional[str] = None, + sso: Optional[str] = None, + ): + self.email: Optional[str] = email + self.password: Optional[str] = password + self.sso: Optional[str] = sso + self.session: httpx.AsyncClient = httpx.AsyncClient() + if self.sso is not None: + self.session.cookies.set("ACT_SSO_COOKIE", self.sso) + @property def AccessToken(self) -> Optional[str]: """ @@ -107,19 +118,32 @@ async def SubmitLogin(self): if res.status_code != 200: raise LoginFailure(f"Failed to login (HTTP {res.status_code})") - - -async def Login(email: str, password: str) -> Client: + elif isinstance(data := await JSONorText(res), dict): + if data.get("success") is not True: + # The API tends to return HTTP 200 even when an error occurs + raise LoginFailure( + f"Failed to login (HTTP {res.status_code}), " + + data.get("token", data) + ) + + +async def Login( + email: Optional[str] = None, + password: Optional[str] = None, + sso: Optional[str] = None, +) -> Client: """ Convenience function to make login with the Call of Duty authorization flow - as easy as possible. + as easy as possible. Requires one of email and password or sso cookie value. Parameters ---------- - email : str + email : str, optional Activision account email address. - password : str + password : str, optional Activision account password. + sso: str, optional + Activision single sign-on cookie value. Returns ------- @@ -127,9 +151,16 @@ async def Login(email: str, password: str) -> Client: Authenticated Call of Duty client. """ - auth: Auth = Auth(email, password) + auth: Auth = Auth(email, password, sso) + + if (email is None) and (sso is None): + raise LoginFailure("Failed to login, insufficient credentials provided") + elif (email is not None) and (password is not None): + await auth.RegisterDevice() + await auth.SubmitLogin() - await auth.RegisterDevice() - await auth.SubmitLogin() + return Client(HTTP(auth)) + elif sso is not None: + await auth.RegisterDevice() - return Client(HTTP(auth)) + return Client(HTTP(auth)) diff --git a/test.py b/test.py index 8921959..0477712 100644 --- a/test.py +++ b/test.py @@ -9,9 +9,12 @@ async def main(): load_dotenv() - client = await callofduty.Login( - os.environ["ATVI_EMAIL"], os.environ["ATVI_PASSWORD"] - ) + + # client = await callofduty.Login( + # os.environ["ATVI_EMAIL"], os.environ["ATVI_PASSWORD"] + # ) + # OR + # client = await callofduty.Login(sso=os.environ["ATVI_SSO"]) # season = await client.GetLootSeason(Title.BlackOps4, 3) # print(f"{season.title.name}: {season.name}") @@ -43,10 +46,10 @@ async def main(): # for account in accounts: # print(f"{account.username} ({account.platform.name})") - # player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930") + # player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207") # print(f"{player.username} ({player.platform.name})") - # player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930") + # player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207") # summary = await player.matchesSummary(Title.ModernWarfare, Mode.Warzone, limit=20) # print(summary) @@ -65,13 +68,13 @@ async def main(): # print(f"#{entry.rank}: {entry.username} ({entry.platform.name})") # leaderboard = await client.GetPlayerLeaderboard( - # Title.BlackOps4, Platform.BattleNet, "Mxtive#1930" + # Title.BlackOps4, Platform.BattleNet, "Yeah#11207" # ) # for entry in leaderboard.entries: - # if entry.username == "Mxtive#1930": + # if entry.username == "Yeah#11207": # print(f"#{entry.rank}: {entry.username} ({entry.platform.name})") - # player = await client.GetPlayer(Platform.Steam, "RdJokr") + # player = await client.GetPlayer(Platform.Steam, "Mxtive") # leaderboard = await player.leaderboard(Title.WWII) # for entry in leaderboard.entries: # if entry.username == player.username: @@ -112,11 +115,11 @@ async def main(): # for mode in maps[mapName]: # print(f" - {mode}") - # match = (await client.GetPlayerMatches(Platform.Activision, "Yeah#8649242", Title.ModernWarfare, Mode.Warzone, limit=3))[0] + # match = (await client.GetPlayerMatches(Platform.BattleNet, "Yeah#11207", Title.ModernWarfare, Mode.Warzone, limit=3))[0] # teams = await match.teams() # print(teams) - # player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930") + # player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207") # match = (await player.matches(Title.ModernWarfare, Mode.Multiplayer, limit=3))[1] # match = await client.GetMatch(Title.ModernWarfare, Platform.Activision, match.id) # teams = await match.teams() @@ -126,7 +129,7 @@ async def main(): # details = await match.details() # print(details) - # player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930") + # player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207") # match = (await player.matches(Title.ModernWarfare, Mode.Multiplayer, limit=3))[1] # match = await client.GetFullMatch(Platform.Activision, Title.ModernWarfare, Mode.Multiplayer, match.id) # print(match) @@ -135,7 +138,7 @@ async def main(): # for player in results: # print(f"{player.username} ({player.platform.name})") - # player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930") + # player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207") # profile = await player.profile(Title.ModernWarfare, Mode.Multiplayer) # print(profile) @@ -233,7 +236,7 @@ async def main(): # if member.username != squad.owner.username: # print(f"Member: {member.username} ({member.platform.name})") - # squad = await client.GetPlayerSquad(Platform.Activision, "Yeah#8649242") + # squad = await client.GetPlayerSquad(Platform.Activision, "Yeah#11207") # print(f"{squad.name} - {squad.description}") # print(f"Owner: {squad.owner.username} ({squad.owner.platform.name})") # for member in squad.members: