Skip to content
This repository was archived by the owner on Dec 28, 2021. It is now read-only.

Commit 9952f05

Browse files
committed
Add authentication with Activision Single Sign-On
1 parent c7c5aab commit 9952f05

File tree

2 files changed

+64
-30
lines changed

2 files changed

+64
-30
lines changed

callofduty/auth.py

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from .client import Client
88
from .errors import LoginFailure
9-
from .http import HTTP
9+
from .http import HTTP, JSONorText
1010

1111
log: logging.Logger = logging.getLogger(__name__)
1212

@@ -17,10 +17,12 @@ class Auth:
1717
1818
Parameters
1919
----------
20-
email : str
20+
email : str, optional
2121
Activision account email address.
22-
password : str
22+
password : str, optional
2323
Activision account password.
24+
sso : str, optional
25+
Activision single sign-on cookie value.
2426
"""
2527

2628
loginUrl: str = "https://profile.callofduty.com/cod/mapp/login"
@@ -29,12 +31,21 @@ class Auth:
2931
_accessToken: Optional[str] = None
3032
_deviceId: Optional[str] = None
3133

32-
def __init__(self, email: str, password: str):
33-
self.email: str = email
34-
self.password: str = password
35-
34+
def __init__(
35+
self,
36+
email: Optional[str] = None,
37+
password: Optional[str] = None,
38+
sso: Optional[str] = None,
39+
):
40+
self.email: Optional[str] = email
41+
self.password: Optional[str] = password
42+
self.sso: Optional[str] = sso
43+
3644
self.session: httpx.AsyncClient = httpx.AsyncClient()
3745

46+
if self.sso is not None:
47+
self.session.cookies.set("ACT_SSO_COOKIE", self.sso)
48+
3849
@property
3950
def AccessToken(self) -> Optional[str]:
4051
"""
@@ -107,29 +118,49 @@ async def SubmitLogin(self):
107118

108119
if res.status_code != 200:
109120
raise LoginFailure(f"Failed to login (HTTP {res.status_code})")
110-
111-
112-
async def Login(email: str, password: str) -> Client:
121+
elif isinstance(data := await JSONorText(res), dict):
122+
if data.get("success") is not True:
123+
# The API tends to return HTTP 200 even when an error occurs
124+
raise LoginFailure(
125+
f"Failed to login (HTTP {res.status_code}), "
126+
+ data.get("token", data)
127+
)
128+
129+
130+
async def Login(
131+
email: Optional[str] = None,
132+
password: Optional[str] = None,
133+
sso: Optional[str] = None,
134+
) -> Client:
113135
"""
114136
Convenience function to make login with the Call of Duty authorization flow
115-
as easy as possible.
137+
as easy as possible. Requires one of email and password or sso cookie value.
116138
117139
Parameters
118140
----------
119-
email : str
141+
email : str, optional
120142
Activision account email address.
121-
password : str
143+
password : str, optional
122144
Activision account password.
145+
sso: str, optional
146+
Activision single sign-on cookie value.
123147
124148
Returns
125149
-------
126150
object
127151
Authenticated Call of Duty client.
128152
"""
129153

130-
auth: Auth = Auth(email, password)
154+
auth: Auth = Auth(email, password, sso)
155+
156+
if (email is None) and (sso is None):
157+
raise LoginFailure("Failed to login, insufficient credentials provided")
158+
elif (email is not None) and (password is not None):
159+
await auth.RegisterDevice()
160+
await auth.SubmitLogin()
131161

132-
await auth.RegisterDevice()
133-
await auth.SubmitLogin()
162+
return Client(HTTP(auth))
163+
elif sso is not None:
164+
await auth.RegisterDevice()
134165

135-
return Client(HTTP(auth))
166+
return Client(HTTP(auth))

test.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99

1010
async def main():
1111
load_dotenv()
12-
client = await callofduty.Login(
13-
os.environ["ATVI_EMAIL"], os.environ["ATVI_PASSWORD"]
14-
)
12+
13+
# client = await callofduty.Login(
14+
# os.environ["ATVI_EMAIL"], os.environ["ATVI_PASSWORD"]
15+
# )
16+
# OR
17+
# client = await callofduty.Login(sso=os.environ["ATVI_SSO"])
1518

1619
# season = await client.GetLootSeason(Title.BlackOps4, 3)
1720
# print(f"{season.title.name}: {season.name}")
@@ -43,10 +46,10 @@ async def main():
4346
# for account in accounts:
4447
# print(f"{account.username} ({account.platform.name})")
4548

46-
# player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930")
49+
# player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207")
4750
# print(f"{player.username} ({player.platform.name})")
4851

49-
# player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930")
52+
# player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207")
5053
# summary = await player.matchesSummary(Title.ModernWarfare, Mode.Warzone, limit=20)
5154
# print(summary)
5255

@@ -65,13 +68,13 @@ async def main():
6568
# print(f"#{entry.rank}: {entry.username} ({entry.platform.name})")
6669

6770
# leaderboard = await client.GetPlayerLeaderboard(
68-
# Title.BlackOps4, Platform.BattleNet, "Mxtive#1930"
71+
# Title.BlackOps4, Platform.BattleNet, "Yeah#11207"
6972
# )
7073
# for entry in leaderboard.entries:
71-
# if entry.username == "Mxtive#1930":
74+
# if entry.username == "Yeah#11207":
7275
# print(f"#{entry.rank}: {entry.username} ({entry.platform.name})")
7376

74-
# player = await client.GetPlayer(Platform.Steam, "RdJokr")
77+
# player = await client.GetPlayer(Platform.Steam, "Mxtive")
7578
# leaderboard = await player.leaderboard(Title.WWII)
7679
# for entry in leaderboard.entries:
7780
# if entry.username == player.username:
@@ -112,11 +115,11 @@ async def main():
112115
# for mode in maps[mapName]:
113116
# print(f" - {mode}")
114117

115-
# match = (await client.GetPlayerMatches(Platform.Activision, "Yeah#8649242", Title.ModernWarfare, Mode.Warzone, limit=3))[0]
118+
# match = (await client.GetPlayerMatches(Platform.BattleNet, "Yeah#11207", Title.ModernWarfare, Mode.Warzone, limit=3))[0]
116119
# teams = await match.teams()
117120
# print(teams)
118121

119-
# player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930")
122+
# player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207")
120123
# match = (await player.matches(Title.ModernWarfare, Mode.Multiplayer, limit=3))[1]
121124
# match = await client.GetMatch(Title.ModernWarfare, Platform.Activision, match.id)
122125
# teams = await match.teams()
@@ -126,7 +129,7 @@ async def main():
126129
# details = await match.details()
127130
# print(details)
128131

129-
# player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930")
132+
# player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207")
130133
# match = (await player.matches(Title.ModernWarfare, Mode.Multiplayer, limit=3))[1]
131134
# match = await client.GetFullMatch(Platform.Activision, Title.ModernWarfare, Mode.Multiplayer, match.id)
132135
# print(match)
@@ -135,7 +138,7 @@ async def main():
135138
# for player in results:
136139
# print(f"{player.username} ({player.platform.name})")
137140

138-
# player = await client.GetPlayer(Platform.BattleNet, "Mxtive#1930")
141+
# player = await client.GetPlayer(Platform.BattleNet, "Yeah#11207")
139142
# profile = await player.profile(Title.ModernWarfare, Mode.Multiplayer)
140143
# print(profile)
141144

@@ -233,7 +236,7 @@ async def main():
233236
# if member.username != squad.owner.username:
234237
# print(f"Member: {member.username} ({member.platform.name})")
235238

236-
# squad = await client.GetPlayerSquad(Platform.Activision, "Yeah#8649242")
239+
# squad = await client.GetPlayerSquad(Platform.Activision, "Yeah#11207")
237240
# print(f"{squad.name} - {squad.description}")
238241
# print(f"Owner: {squad.owner.username} ({squad.owner.platform.name})")
239242
# for member in squad.members:

0 commit comments

Comments
 (0)