Skip to content

Commit 8cbf7fa

Browse files
committed
feat: Start implementing XAL
1 parent 03c7ce1 commit 8cbf7fa

6 files changed

Lines changed: 66 additions & 39 deletions

File tree

tests/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
XAUResponse,
1212
XSTSResponse,
1313
)
14+
from xbox.webapi.authentication.xal import XALManager
1415
from xbox.webapi.common.request_signer import RequestSigner
1516
from xbox.webapi.common.signed_session import SignedSession
1617

@@ -30,6 +31,14 @@ async def auth_mgr(event_loop):
3031
await session.aclose()
3132

3233

34+
@pytest_asyncio.fixture(scope="function")
35+
async def xal_mgr(event_loop):
36+
session = SignedSession()
37+
mgr = XALManager(session)
38+
yield mgr
39+
await session.aclose()
40+
41+
3342
@pytest.fixture(scope="function")
3443
def xbl_client(auth_mgr):
3544
return XboxLiveClient(auth_mgr)

tests/test_auth.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from datetime import datetime, timedelta, timezone
2-
import uuid
32

43
from httpx import Response
54
import pytest
@@ -99,17 +98,6 @@ async def test_get_title_endpoints(respx_mock, auth_mgr):
9998
assert route.called
10099

101100

102-
@pytest.mark.asyncio
103-
async def test_get_device_token(respx_mock, auth_mgr):
104-
route = respx_mock.post(
105-
"https://device.auth.xboxlive.com/device/authenticate"
106-
).mock(return_value=Response(200, json=get_response_json("auth_device_token")))
107-
resp = await auth_mgr.request_device_token(
108-
uuid.UUID("9c493431-5462-4a4a-a247-f6420396318d")
109-
)
110-
assert route.called
111-
112-
113101
@pytest.mark.asyncio
114102
async def test_xsts_properties(auth_mgr):
115103
assert auth_mgr.xsts_token.xuid == "2669321029139235"

tests/test_signed_session.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ async def test_sending_signed_request(synthetic_request_signer, respx_mock):
3434
assert route.called
3535
assert resp.request.headers.get("Signature") is not None
3636

37+
3738
@pytest.mark.asyncio
3839
async def test_sending_signed(synthetic_request_signer, respx_mock):
3940
route = respx_mock.post("https://xsts.auth.xboxlive.com").mock(
@@ -42,10 +43,10 @@ async def test_sending_signed(synthetic_request_signer, respx_mock):
4243

4344
signed_session = SignedSession(synthetic_request_signer)
4445

45-
method="POST"
46-
url="https://xsts.auth.xboxlive.com/xsts/authorize"
47-
headers={"x-xbl-contract-version": "1"}
48-
data={
46+
method = "POST"
47+
url = "https://xsts.auth.xboxlive.com/xsts/authorize"
48+
headers = {"x-xbl-contract-version": "1"}
49+
data = {
4950
"RelyingParty": "http://xboxlive.com",
5051
"TokenType": "JWT",
5152
"Properties": {
@@ -58,4 +59,4 @@ async def test_sending_signed(synthetic_request_signer, respx_mock):
5859
resp = await signed_session.send_signed(method, url, headers=headers, data=data)
5960

6061
assert route.called
61-
assert resp.request.headers.get("Signature") is not None
62+
assert resp.request.headers.get("Signature") is not None

tests/test_xal.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from datetime import datetime, timedelta, timezone
2+
import uuid
3+
4+
from httpx import Response
5+
import pytest
6+
7+
from tests.common import get_response_json
8+
9+
10+
@pytest.mark.asyncio
11+
async def test_get_device_token(respx_mock, xal_mgr):
12+
route = respx_mock.post(
13+
"https://device.auth.xboxlive.com/device/authenticate"
14+
).mock(return_value=Response(200, json=get_response_json("auth_device_token")))
15+
resp = await xal_mgr.request_device_token(
16+
uuid.UUID("9c493431-5462-4a4a-a247-f6420396318d")
17+
)
18+
assert route.called

xbox/webapi/authentication/manager.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,12 @@
55
"""
66
import logging
77
from typing import List, Optional
8-
import uuid
98

109
import httpx
1110

1211
from xbox.webapi.authentication.models import (
1312
OAuth2TokenResponse,
1413
TitleEndpointsResponse,
15-
XADResponse,
1614
XAUResponse,
1715
XSTSResponse,
1816
)
@@ -170,23 +168,3 @@ async def request_xsts_token(
170168
raise AuthenticationException()
171169
resp.raise_for_status()
172170
return XSTSResponse(**resp.json())
173-
174-
async def request_device_token(self, device_id: uuid.UUID) -> XADResponse:
175-
url = "https://device.auth.xboxlive.com/device/authenticate"
176-
headers = {"x-xbl-contract-version": "1"}
177-
data = {
178-
"RelyingParty": "http://auth.xboxlive.com",
179-
"TokenType": "JWT",
180-
"Properties": {
181-
"AuthMethod": "ProofOfPossession",
182-
"Id": str(device_id).upper(),
183-
"DeviceType": "Win32",
184-
"Version": "10.0.22000.194",
185-
"ProofKey": self.session.request_signer.proof_field,
186-
},
187-
}
188-
189-
request = httpx.Request("POST", url, headers=headers, json=data)
190-
resp = await self.session.send_signed(request)
191-
resp.raise_for_status()
192-
return XADResponse(**resp.json())

xbox/webapi/authentication/xal.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""
2+
Xbox Authentication Library
3+
4+
Authenticate with Windows Live Server and Xbox Live (used by mobile Xbox Apps)
5+
"""
6+
import uuid
7+
8+
from xbox.webapi.authentication.models import XADResponse
9+
from xbox.webapi.common.signed_session import SignedSession
10+
11+
12+
class XALManager:
13+
def __init__(self, session: SignedSession):
14+
self.session = session
15+
16+
async def request_device_token(self, device_id: uuid.UUID) -> XADResponse:
17+
url = "https://device.auth.xboxlive.com/device/authenticate"
18+
headers = {"x-xbl-contract-version": "1"}
19+
data = {
20+
"RelyingParty": "http://auth.xboxlive.com",
21+
"TokenType": "JWT",
22+
"Properties": {
23+
"AuthMethod": "ProofOfPossession",
24+
"Id": str(device_id).upper(),
25+
"DeviceType": "Win32",
26+
"Version": "10.0.22000.194",
27+
"ProofKey": self.session.request_signer.proof_field,
28+
},
29+
}
30+
31+
resp = await self.session.send_signed("POST", url, headers=headers, json=data)
32+
resp.raise_for_status()
33+
return XADResponse(**resp.json())

0 commit comments

Comments
 (0)