halo-infinite-api 1.2.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/authentication/halo-authentication-client.d.ts +4 -5
- package/dist/authentication/halo-authentication-client.js +23 -69
- package/dist/authentication/halo-authentication-client.js.map +1 -1
- package/dist/authentication/xbox-authentication-client.d.ts +23 -10
- package/dist/authentication/xbox-authentication-client.js +92 -64
- package/dist/authentication/xbox-authentication-client.js.map +1 -1
- package/dist/core/halo-infinite-client.d.ts +9 -8
- package/dist/core/halo-infinite-client.js +20 -35
- package/dist/core/halo-infinite-client.js.map +1 -1
- package/dist/core/spartan-token-fetchers/auto-xsts-sartan-token-provider.d.ts +11 -0
- package/dist/core/spartan-token-fetchers/auto-xsts-sartan-token-provider.js +43 -0
- package/dist/core/spartan-token-fetchers/auto-xsts-sartan-token-provider.js.map +1 -0
- package/dist/core/spartan-token-fetchers/index.d.ts +3 -0
- package/dist/core/spartan-token-fetchers/index.js +2 -0
- package/dist/core/spartan-token-fetchers/index.js.map +1 -0
- package/dist/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.d.ts +12 -0
- package/dist/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.js +26 -0
- package/dist/core/spartan-token-fetchers/static-xsts-ticket-token-spartan-token-provider.js.map +1 -0
- package/dist/core/spartan-token-providers/auto-xsts-spartan-token-provider.d.ts +11 -0
- package/dist/core/spartan-token-providers/auto-xsts-spartan-token-provider.js +31 -0
- package/dist/core/spartan-token-providers/auto-xsts-spartan-token-provider.js.map +1 -0
- package/dist/core/spartan-token-providers/index.d.ts +3 -0
- package/dist/core/spartan-token-providers/index.js +2 -0
- package/dist/core/spartan-token-providers/index.js.map +1 -0
- package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.d.ts +12 -0
- package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.js +25 -0
- package/dist/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.js.map +1 -0
- package/dist/core/token-persister.d.ts +4 -0
- package/dist/core/token-persister.js +2 -0
- package/dist/core/token-persister.js.map +1 -0
- package/dist/core/token-persisters/in-memory-token-persister.d.ts +2 -0
- package/dist/core/token-persisters/in-memory-token-persister.js +10 -0
- package/dist/core/token-persisters/in-memory-token-persister.js.map +1 -0
- package/dist/core/token-persisters/index.d.ts +4 -0
- package/dist/core/token-persisters/index.js +2 -0
- package/dist/core/token-persisters/index.js.map +1 -0
- package/dist/core/token-persisters/local-storage-token-persister.d.ts +2 -0
- package/dist/core/token-persisters/local-storage-token-persister.js +15 -0
- package/dist/core/token-persisters/local-storage-token-persister.js.map +1 -0
- package/dist/core/token-persisters/node-fs-token-persister.d.ts +2 -0
- package/dist/core/token-persisters/node-fs-token-persister.js +24 -0
- package/dist/core/token-persisters/node-fs-token-persister.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/util/expiry-token-cache.d.ts +9 -0
- package/dist/util/expiry-token-cache.js +48 -0
- package/dist/util/expiry-token-cache.js.map +1 -0
- package/dist/util/resolvable-promise.d.ts +8 -0
- package/dist/util/resolvable-promise.js +31 -0
- package/dist/util/resolvable-promise.js.map +1 -0
- package/package.json +3 -2
- package/src/authentication/halo-authentication-client.ts +30 -72
- package/src/authentication/xbox-authentication-client.ts +120 -83
- package/src/core/halo-infinite-client.ts +30 -66
- package/src/core/spartan-token-providers/auto-xsts-spartan-token-provider.ts +54 -0
- package/src/core/spartan-token-providers/index.ts +3 -0
- package/src/core/spartan-token-providers/static-xsts-ticket-token-spartan-token-provider.ts +35 -0
- package/src/core/token-persisters/in-memory-token-persister.ts +12 -0
- package/src/core/token-persisters/index.ts +4 -0
- package/src/core/token-persisters/local-storage-token-persister.ts +15 -0
- package/src/core/token-persisters/node-fs-token-persister.ts +23 -0
- package/src/index.ts +8 -0
- package/src/util/expiry-token-cache.ts +51 -0
- package/src/util/resolvable-promise.ts +32 -0
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ The core requirement to use the endpoints in the library is to have a Spartan to
|
|
|
21
21
|
>
|
|
22
22
|
> The Spartan token is associated with _your identity_ and _your account_. **Do not share it** with anyone, under any circumstances. The API wrapper does not explicitly store it anywhere. It's your responsibility to make sure that it's secure and not available to anyone else.
|
|
23
23
|
|
|
24
|
-
If you want to automatically generate the Spartan token, you can do so with the help of
|
|
24
|
+
If you want to automatically generate the Spartan token, you can do so with the help of this package without having to worry about doing any of the REST API calls yourself. Before you get started, make sure that you [register an Azure Active Directory application](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app). You will need it in order to log in with your Microsoft account, that will be used to generate the token. Because this is just for you, you can use `https://localhost` as the redirect URI when you create the application, unless you're thinking of productizing whatever you're building.
|
|
25
25
|
|
|
26
26
|
Once you have the application registered, you can use the following code to automatically generate the token and call endpoints:
|
|
27
27
|
|
|
@@ -7,11 +7,10 @@ export declare class HaloAuthenticationClient {
|
|
|
7
7
|
private readonly fetchXstsToken;
|
|
8
8
|
private readonly loadToken;
|
|
9
9
|
private readonly saveToken;
|
|
10
|
-
private
|
|
11
|
-
constructor(fetchXstsToken: () => Promise<string
|
|
12
|
-
token
|
|
13
|
-
expiresAt
|
|
10
|
+
private spartanTokenCache;
|
|
11
|
+
constructor(fetchXstsToken: () => Promise<string> | string, loadToken: () => Promise<{
|
|
12
|
+
token: string;
|
|
13
|
+
expiresAt: unknown;
|
|
14
14
|
} | null>, saveToken: (token: Token) => Promise<void>);
|
|
15
15
|
getSpartanToken(): Promise<string>;
|
|
16
|
-
private fetchSpartanToken;
|
|
17
16
|
}
|
|
@@ -1,80 +1,23 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { DateTime } from "luxon";
|
|
3
3
|
import { coalesceDateTime } from "../util/date-time";
|
|
4
|
+
import { ExpiryTokenCache } from "../util/expiry-token-cache";
|
|
4
5
|
export class HaloAuthenticationClient {
|
|
5
6
|
fetchXstsToken;
|
|
6
7
|
loadToken;
|
|
7
8
|
saveToken;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
// Wait for them to finish, then check for validity
|
|
18
|
-
const currentToken = await this.currentTokenPromise;
|
|
19
|
-
if (currentToken.expiresAt > DateTime.now()) {
|
|
20
|
-
// Current token is valid, return it
|
|
21
|
-
return currentToken.token;
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
// Current token expired, start a new promise
|
|
25
|
-
let promiseResolver;
|
|
26
|
-
let promiseRejector;
|
|
27
|
-
this.currentTokenPromise = new Promise((resolve, reject) => {
|
|
28
|
-
promiseResolver = resolve;
|
|
29
|
-
promiseRejector = reject;
|
|
30
|
-
});
|
|
31
|
-
try {
|
|
32
|
-
const xstsToken = await this.fetchXstsToken();
|
|
33
|
-
const newToken = await this.fetchSpartanToken(xstsToken);
|
|
34
|
-
promiseResolver(newToken);
|
|
35
|
-
await this.saveToken(newToken);
|
|
36
|
-
return newToken.token;
|
|
37
|
-
}
|
|
38
|
-
catch (e) {
|
|
39
|
-
promiseRejector(e);
|
|
40
|
-
throw e;
|
|
41
|
-
}
|
|
9
|
+
spartanTokenCache = new ExpiryTokenCache(async () => {
|
|
10
|
+
const persistedToken = await this.loadToken();
|
|
11
|
+
if (persistedToken?.expiresAt) {
|
|
12
|
+
const currentToken = {
|
|
13
|
+
token: persistedToken.token,
|
|
14
|
+
expiresAt: coalesceDateTime(persistedToken.expiresAt),
|
|
15
|
+
};
|
|
16
|
+
if (currentToken.expiresAt && currentToken.expiresAt > DateTime.now()) {
|
|
17
|
+
return currentToken;
|
|
42
18
|
}
|
|
43
19
|
}
|
|
44
|
-
|
|
45
|
-
// We are the first caller, create a promise to block subsequent callers
|
|
46
|
-
let promiseResolver;
|
|
47
|
-
let promiseRejector;
|
|
48
|
-
this.currentTokenPromise = new Promise((resolve, reject) => {
|
|
49
|
-
promiseResolver = resolve;
|
|
50
|
-
promiseRejector = reject;
|
|
51
|
-
});
|
|
52
|
-
try {
|
|
53
|
-
const loadedToken = await this.loadToken();
|
|
54
|
-
const currentToken = {
|
|
55
|
-
token: loadedToken?.token ?? "",
|
|
56
|
-
expiresAt: coalesceDateTime(loadedToken?.expiresAt),
|
|
57
|
-
};
|
|
58
|
-
if (currentToken.expiresAt && currentToken.expiresAt > DateTime.now()) {
|
|
59
|
-
// Current token is valid, return it and alert other callers if applicable
|
|
60
|
-
promiseResolver(currentToken);
|
|
61
|
-
return currentToken.token;
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
const xstsToken = await this.fetchXstsToken();
|
|
65
|
-
const newToken = await this.fetchSpartanToken(xstsToken);
|
|
66
|
-
promiseResolver(newToken);
|
|
67
|
-
await this.saveToken(newToken);
|
|
68
|
-
return newToken.token;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch (e) {
|
|
72
|
-
promiseRejector(e);
|
|
73
|
-
throw e;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
async fetchSpartanToken(xstsToken) {
|
|
20
|
+
const xstsToken = await this.fetchXstsToken();
|
|
78
21
|
const tokenRequest = {
|
|
79
22
|
Audience: "urn:343:s3:services",
|
|
80
23
|
MinVersion: "4",
|
|
@@ -91,10 +34,21 @@ export class HaloAuthenticationClient {
|
|
|
91
34
|
"Content-Type": "application/json; charset=utf-8",
|
|
92
35
|
},
|
|
93
36
|
});
|
|
94
|
-
|
|
37
|
+
const newToken = {
|
|
95
38
|
token: response.data.SpartanToken,
|
|
96
39
|
expiresAt: DateTime.fromISO(response.data.ExpiresUtc.ISO8601Date),
|
|
97
40
|
};
|
|
41
|
+
await this.saveToken(newToken);
|
|
42
|
+
return newToken;
|
|
43
|
+
});
|
|
44
|
+
constructor(fetchXstsToken, loadToken, saveToken) {
|
|
45
|
+
this.fetchXstsToken = fetchXstsToken;
|
|
46
|
+
this.loadToken = loadToken;
|
|
47
|
+
this.saveToken = saveToken;
|
|
48
|
+
}
|
|
49
|
+
async getSpartanToken() {
|
|
50
|
+
const { token } = await this.spartanTokenCache.getToken();
|
|
51
|
+
return token;
|
|
98
52
|
}
|
|
99
53
|
}
|
|
100
54
|
//# sourceMappingURL=halo-authentication-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"halo-authentication-client.js","sourceRoot":"","sources":["../../src/authentication/halo-authentication-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"halo-authentication-client.js","sourceRoot":"","sources":["../../src/authentication/halo-authentication-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAO9D,MAAM,OAAO,wBAAwB;IA+ChB;IACA;IAIA;IAnDX,iBAAiB,GAAG,IAAI,gBAAgB,CAAC,KAAK,IAAI,EAAE;QAC1D,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAE9C,IAAI,cAAc,EAAE,SAAS,EAAE;YAC7B,MAAM,YAAY,GAAG;gBACnB,KAAK,EAAE,cAAc,CAAC,KAAK;gBAC3B,SAAS,EAAE,gBAAgB,CAAC,cAAc,CAAC,SAAS,CAAa;aAClE,CAAC;YACF,IAAI,YAAY,CAAC,SAAS,IAAI,YAAY,CAAC,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE;gBACrE,OAAO,YAAY,CAAC;aACrB;SACF;QAED,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAE9C,MAAM,YAAY,GAAwB;YACxC,QAAQ,EAAE,qBAAqB;YAC/B,UAAU,EAAE,GAAG;YACf,KAAK,EAAE;gBACL;oBACE,KAAK,EAAE,SAAS;oBAChB,SAAS,EAAE,aAAa;iBACzB;aACF;SACF,CAAC;QACF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAC/B,qDAAqD,EACrD,YAAY,EACZ;YACE,OAAO,EAAE;gBACP,YAAY,EACV,gEAAgE;gBAClE,cAAc,EAAE,iCAAiC;aAClD;SACF,CACF,CAAC;QAEF,MAAM,QAAQ,GAAG;YACf,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,YAAY;YACjC,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;SAClE,CAAC;QACF,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC/B,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,YACmB,cAA8C,EAC9C,SAGR,EACQ,SAA0C;QAL1C,mBAAc,GAAd,cAAc,CAAgC;QAC9C,cAAS,GAAT,SAAS,CAGjB;QACQ,cAAS,GAAT,SAAS,CAAiC;IAC1D,CAAC;IAEG,KAAK,CAAC,eAAe;QAC1B,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;QAC1D,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DateTime } from "luxon";
|
|
2
|
-
import {
|
|
2
|
+
import { TokenPersister } from "../core/token-persisters";
|
|
3
3
|
export declare enum RelyingParty {
|
|
4
4
|
Xbox = "http://xboxlive.com",
|
|
5
5
|
Halo = "https://prod.xsts.halowaypoint.com/"
|
|
@@ -13,20 +13,33 @@ export declare class XboxAuthenticationClient {
|
|
|
13
13
|
private readonly clientId;
|
|
14
14
|
private readonly redirectUri;
|
|
15
15
|
private readonly getAuthCode;
|
|
16
|
-
private readonly
|
|
17
|
-
private
|
|
18
|
-
private
|
|
16
|
+
private readonly tokenPersister?;
|
|
17
|
+
private accessTokenPromise;
|
|
18
|
+
private userTokenCache;
|
|
19
|
+
private xstsTicketCache;
|
|
19
20
|
private readonly httpClient;
|
|
20
|
-
constructor(clientId: string, redirectUri: string, getAuthCode: (authorizeUrl: string) => Promise<string>,
|
|
21
|
-
token?: string;
|
|
22
|
-
expiresAt?: unknown;
|
|
23
|
-
refreshToken?: string;
|
|
24
|
-
} | null>, saveToken: (token: XboxAuthenticationToken) => Promise<void>);
|
|
21
|
+
constructor(clientId: string, redirectUri: string, getAuthCode: (authorizeUrl: string) => Promise<string>, tokenPersister?: TokenPersister | undefined);
|
|
25
22
|
private getPkce;
|
|
26
23
|
getAccessToken(): Promise<string>;
|
|
27
24
|
private fetchOauth2Token;
|
|
28
25
|
private refreshOAuth2Token;
|
|
29
26
|
getUserToken(accessToken: string): Promise<string>;
|
|
30
|
-
getXstsTicket(userToken: string, relyingParty: RelyingParty): Promise<
|
|
27
|
+
getXstsTicket(userToken: string, relyingParty: RelyingParty): Promise<{
|
|
28
|
+
expiresAt: DateTime;
|
|
29
|
+
IssueInstant: string;
|
|
30
|
+
NotAfter: string;
|
|
31
|
+
Token: string;
|
|
32
|
+
DisplayClaims: {
|
|
33
|
+
xui: [{
|
|
34
|
+
uhs: string;
|
|
35
|
+
gtg: string;
|
|
36
|
+
xid: string;
|
|
37
|
+
agg: string;
|
|
38
|
+
usr: string;
|
|
39
|
+
utr: string;
|
|
40
|
+
prv: string;
|
|
41
|
+
}];
|
|
42
|
+
};
|
|
43
|
+
}>;
|
|
31
44
|
getXboxLiveV3Token: (userHash: string, userToken: string) => string;
|
|
32
45
|
}
|
|
@@ -2,6 +2,8 @@ import axios from "axios";
|
|
|
2
2
|
import pkceChallenge from "pkce-challenge";
|
|
3
3
|
import { DateTime } from "luxon";
|
|
4
4
|
import { coalesceDateTime } from "../util/date-time";
|
|
5
|
+
import { ResolvablePromise } from "../util/resolvable-promise";
|
|
6
|
+
import { ExpiryTokenCache } from "../util/expiry-token-cache";
|
|
5
7
|
const SCOPES = ["Xboxlive.signin", "Xboxlive.offline_access"];
|
|
6
8
|
export var RelyingParty;
|
|
7
9
|
(function (RelyingParty) {
|
|
@@ -12,60 +14,114 @@ export class XboxAuthenticationClient {
|
|
|
12
14
|
clientId;
|
|
13
15
|
redirectUri;
|
|
14
16
|
getAuthCode;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
tokenPersister;
|
|
18
|
+
accessTokenPromise = undefined;
|
|
19
|
+
userTokenCache = new ExpiryTokenCache(async (accessToken) => {
|
|
20
|
+
const persistedToken = await this.tokenPersister?.load("xbox.userToken");
|
|
21
|
+
if (persistedToken?.expiresAt) {
|
|
22
|
+
const expiresAt = coalesceDateTime(persistedToken.expiresAt);
|
|
23
|
+
if (expiresAt && expiresAt > DateTime.now()) {
|
|
24
|
+
return { ...persistedToken, expiresAt };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const response = await this.httpClient.post("https://user.auth.xboxlive.com/user/authenticate", {
|
|
28
|
+
RelyingParty: "http://auth.xboxlive.com",
|
|
29
|
+
TokenType: "JWT",
|
|
30
|
+
Properties: {
|
|
31
|
+
AuthMethod: "RPS",
|
|
32
|
+
SiteName: "user.auth.xboxlive.com",
|
|
33
|
+
RpsTicket: `d=${accessToken}`,
|
|
34
|
+
},
|
|
35
|
+
}, {
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
Accept: "application/json",
|
|
39
|
+
"x-xbl-contract-version": "1",
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
const result = {
|
|
43
|
+
...response.data,
|
|
44
|
+
expiresAt: DateTime.fromISO(response.data.NotAfter),
|
|
45
|
+
};
|
|
46
|
+
await this.tokenPersister?.save("xbox.userToken", result);
|
|
47
|
+
return result;
|
|
48
|
+
});
|
|
49
|
+
xstsTicketCache = new ExpiryTokenCache(async (userToken, relyingParty) => {
|
|
50
|
+
const persistedToken = await this.tokenPersister?.load("xbox.xstsTicket");
|
|
51
|
+
if (persistedToken?.expiresAt) {
|
|
52
|
+
const expiresAt = coalesceDateTime(persistedToken.expiresAt);
|
|
53
|
+
if (expiresAt && expiresAt > DateTime.now()) {
|
|
54
|
+
return { ...persistedToken, expiresAt };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const response = await this.httpClient.post("https://xsts.auth.xboxlive.com/xsts/authorize", {
|
|
58
|
+
RelyingParty: relyingParty,
|
|
59
|
+
TokenType: "JWT",
|
|
60
|
+
Properties: {
|
|
61
|
+
SandboxId: "RETAIL",
|
|
62
|
+
UserTokens: [userToken],
|
|
63
|
+
},
|
|
64
|
+
}, {
|
|
65
|
+
headers: {
|
|
66
|
+
"Content-Type": "application/json",
|
|
67
|
+
Accept: "application/json",
|
|
68
|
+
"x-xbl-contract-version": "1",
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
const result = {
|
|
72
|
+
...response.data,
|
|
73
|
+
expiresAt: DateTime.fromISO(response.data.NotAfter),
|
|
74
|
+
};
|
|
75
|
+
await this.tokenPersister?.save("xbox.xstsTicket", result);
|
|
76
|
+
return result;
|
|
77
|
+
});
|
|
18
78
|
httpClient;
|
|
19
|
-
constructor(clientId, redirectUri, getAuthCode,
|
|
79
|
+
constructor(clientId, redirectUri, getAuthCode, tokenPersister) {
|
|
20
80
|
this.clientId = clientId;
|
|
21
81
|
this.redirectUri = redirectUri;
|
|
22
82
|
this.getAuthCode = getAuthCode;
|
|
23
|
-
this.
|
|
24
|
-
this.saveToken = saveToken;
|
|
83
|
+
this.tokenPersister = tokenPersister;
|
|
25
84
|
this.httpClient = axios.create();
|
|
26
85
|
}
|
|
27
86
|
getPkce() {
|
|
28
|
-
|
|
87
|
+
if (typeof pkceChallenge === "function") {
|
|
88
|
+
return pkceChallenge(43);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
return pkceChallenge.default(43);
|
|
92
|
+
}
|
|
29
93
|
}
|
|
30
94
|
async getAccessToken() {
|
|
31
|
-
if (this.
|
|
95
|
+
if (this.accessTokenPromise) {
|
|
32
96
|
// Someone either already has a token or is in the process of getting one
|
|
33
97
|
// Wait for them to finish, then check for validity
|
|
34
|
-
const currentToken = await this.
|
|
98
|
+
const currentToken = await this.accessTokenPromise;
|
|
35
99
|
if (currentToken.expiresAt > DateTime.now()) {
|
|
36
100
|
// Current token is valid, return it
|
|
37
101
|
return currentToken.token;
|
|
38
102
|
}
|
|
39
103
|
else {
|
|
40
104
|
// Current token expired, start a new promise
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
this.currentTokenPromise = new Promise((resolve, reject) => {
|
|
44
|
-
promiseResolver = resolve;
|
|
45
|
-
promiseRejector = reject;
|
|
46
|
-
});
|
|
105
|
+
this.accessTokenPromise =
|
|
106
|
+
new ResolvablePromise();
|
|
47
107
|
try {
|
|
48
108
|
const newToken = await this.refreshOAuth2Token(currentToken.refreshToken);
|
|
49
|
-
|
|
50
|
-
await this.
|
|
109
|
+
this.accessTokenPromise.resolve(newToken);
|
|
110
|
+
await this.tokenPersister?.save("xbox.accessToken", newToken);
|
|
51
111
|
return newToken.token;
|
|
52
112
|
}
|
|
53
113
|
catch (e) {
|
|
54
|
-
|
|
114
|
+
this.accessTokenPromise.reject(e);
|
|
55
115
|
throw e;
|
|
56
116
|
}
|
|
57
117
|
}
|
|
58
118
|
}
|
|
59
119
|
else {
|
|
60
120
|
// We are the first caller, create a promise to block subsequent callers
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
this.currentTokenPromise = new Promise((resolve, reject) => {
|
|
64
|
-
promiseResolver = resolve;
|
|
65
|
-
promiseRejector = reject;
|
|
66
|
-
});
|
|
121
|
+
this.accessTokenPromise =
|
|
122
|
+
new ResolvablePromise();
|
|
67
123
|
try {
|
|
68
|
-
const loadedToken = await this.
|
|
124
|
+
const loadedToken = await this.tokenPersister?.load("xbox.accessToken");
|
|
69
125
|
const currentToken = {
|
|
70
126
|
...loadedToken,
|
|
71
127
|
token: loadedToken?.token ?? "",
|
|
@@ -73,24 +129,24 @@ export class XboxAuthenticationClient {
|
|
|
73
129
|
};
|
|
74
130
|
if (currentToken.expiresAt && currentToken.expiresAt > DateTime.now()) {
|
|
75
131
|
// Current token is valid, return it and alert other callers if applicable
|
|
76
|
-
|
|
132
|
+
this.accessTokenPromise.resolve(currentToken);
|
|
77
133
|
return currentToken.token;
|
|
78
134
|
}
|
|
79
135
|
else {
|
|
80
136
|
const newToken = await this.fetchOauth2Token();
|
|
81
|
-
|
|
82
|
-
await this.
|
|
137
|
+
this.accessTokenPromise.resolve(newToken);
|
|
138
|
+
await this.tokenPersister?.save("xbox.accessToken", newToken);
|
|
83
139
|
return newToken.token;
|
|
84
140
|
}
|
|
85
141
|
}
|
|
86
142
|
catch (e) {
|
|
87
|
-
|
|
143
|
+
this.accessTokenPromise.reject(e);
|
|
88
144
|
throw e;
|
|
89
145
|
}
|
|
90
146
|
}
|
|
91
147
|
}
|
|
92
148
|
async fetchOauth2Token() {
|
|
93
|
-
const { code_verifier, code_challenge } =
|
|
149
|
+
const { code_verifier, code_challenge } = this.getPkce();
|
|
94
150
|
const authorizeUrl = `https://login.live.com/oauth20_authorize.srf?${new URLSearchParams({
|
|
95
151
|
client_id: this.clientId,
|
|
96
152
|
response_type: "code",
|
|
@@ -119,6 +175,7 @@ export class XboxAuthenticationClient {
|
|
|
119
175
|
};
|
|
120
176
|
}
|
|
121
177
|
async refreshOAuth2Token(refreshToken) {
|
|
178
|
+
const requestStart = DateTime.now();
|
|
122
179
|
const response = await this.httpClient.post("https://login.live.com/oauth20_token.srf", new URLSearchParams({
|
|
123
180
|
grant_type: "refresh_token",
|
|
124
181
|
refresh_token: refreshToken,
|
|
@@ -128,47 +185,18 @@ export class XboxAuthenticationClient {
|
|
|
128
185
|
}), {
|
|
129
186
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
130
187
|
});
|
|
131
|
-
const responseDate = DateTime.fromRFC2822(response.headers["date"]);
|
|
132
188
|
return {
|
|
133
189
|
token: response.data.access_token,
|
|
134
|
-
expiresAt:
|
|
190
|
+
expiresAt: requestStart.plus({ seconds: response.data.expires_in }),
|
|
135
191
|
refreshToken: response.data.refresh_token,
|
|
136
192
|
};
|
|
137
193
|
}
|
|
138
194
|
async getUserToken(accessToken) {
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
TokenType: "JWT",
|
|
142
|
-
Properties: {
|
|
143
|
-
AuthMethod: "RPS",
|
|
144
|
-
SiteName: "user.auth.xboxlive.com",
|
|
145
|
-
RpsTicket: `d=${accessToken}`,
|
|
146
|
-
},
|
|
147
|
-
}, {
|
|
148
|
-
headers: {
|
|
149
|
-
"Content-Type": "application/json",
|
|
150
|
-
Accept: "application/json",
|
|
151
|
-
"x-xbl-contract-version": "1",
|
|
152
|
-
},
|
|
153
|
-
});
|
|
154
|
-
return response.data.Token;
|
|
195
|
+
const { Token } = await this.userTokenCache.getToken(accessToken);
|
|
196
|
+
return Token;
|
|
155
197
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
RelyingParty: relyingParty,
|
|
159
|
-
TokenType: "JWT",
|
|
160
|
-
Properties: {
|
|
161
|
-
SandboxId: "RETAIL",
|
|
162
|
-
UserTokens: [userToken],
|
|
163
|
-
},
|
|
164
|
-
}, {
|
|
165
|
-
headers: {
|
|
166
|
-
"Content-Type": "application/json",
|
|
167
|
-
Accept: "application/json",
|
|
168
|
-
"x-xbl-contract-version": "1",
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
return response.data;
|
|
198
|
+
getXstsTicket(userToken, relyingParty) {
|
|
199
|
+
return this.xstsTicketCache.getToken(userToken, relyingParty);
|
|
172
200
|
}
|
|
173
201
|
getXboxLiveV3Token = (userHash, userToken) => `XBL3.0 x=${userHash};${userToken}`;
|
|
174
202
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xbox-authentication-client.js","sourceRoot":"","sources":["../../src/authentication/xbox-authentication-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAC7C,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"xbox-authentication-client.js","sourceRoot":"","sources":["../../src/authentication/xbox-authentication-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { MapAsset, PlaylistAsset, UgcGameVariantAsset } from "../models/halo-infinite/asset";
|
|
2
|
+
import { AssetKind } from "../models/halo-infinite/asset-kind";
|
|
1
3
|
import { MatchSkill } from "../models/halo-infinite/match-skill";
|
|
2
4
|
import { MatchStats } from "../models/halo-infinite/match-stats";
|
|
3
5
|
import { MatchType } from "../models/halo-infinite/match-type";
|
|
@@ -6,25 +8,20 @@ import { Playlist } from "../models/halo-infinite/playlist";
|
|
|
6
8
|
import { PlaylistCsrContainer } from "../models/halo-infinite/playlist-csr-container";
|
|
7
9
|
import { ServiceRecord } from "../models/halo-infinite/service-record";
|
|
8
10
|
import { UserInfo } from "../models/halo-infinite/user-info";
|
|
9
|
-
import {
|
|
10
|
-
import { AssetKind } from "../models/halo-infinite/asset-kind";
|
|
11
|
+
import { SpartanTokenProvider } from "./spartan-token-providers";
|
|
11
12
|
interface ResultContainer<TValue> {
|
|
12
13
|
Id: string;
|
|
13
14
|
ResultCode: 0 | 1;
|
|
14
15
|
Result: TValue;
|
|
15
16
|
}
|
|
16
|
-
interface TokenPersister {
|
|
17
|
-
load: <T>(tokenName: string) => Promise<T> | T;
|
|
18
|
-
save: (tokenName: string, token: unknown) => Promise<void> | void;
|
|
19
|
-
}
|
|
20
17
|
export type AssetKindTypeMap = {
|
|
21
18
|
[AssetKind.Map]: MapAsset;
|
|
22
19
|
[AssetKind.UgcGameVariant]: UgcGameVariantAsset;
|
|
23
20
|
[AssetKind.Playlist]: PlaylistAsset;
|
|
24
21
|
};
|
|
25
22
|
export declare class HaloInfiniteClient {
|
|
26
|
-
private
|
|
27
|
-
constructor(
|
|
23
|
+
private spartanTokenProvider;
|
|
24
|
+
constructor(spartanTokenProvider: SpartanTokenProvider);
|
|
28
25
|
private executeRequest;
|
|
29
26
|
private executeResultsRequest;
|
|
30
27
|
private executePaginationRequest;
|
|
@@ -37,6 +34,10 @@ export declare class HaloInfiniteClient {
|
|
|
37
34
|
* @param gamerTag - Gamertag to lookup.
|
|
38
35
|
*/
|
|
39
36
|
getUser: (gamerTag: string) => Promise<UserInfo>;
|
|
37
|
+
/** Get gamertag info for several players.
|
|
38
|
+
* @param xuids - Xuids to lookup.
|
|
39
|
+
*/
|
|
40
|
+
getUsers: (xuids: string[]) => Promise<UserInfo[]>;
|
|
40
41
|
/** Get service record for a player.
|
|
41
42
|
* @param gamerTag - Gamertag to lookup.
|
|
42
43
|
*/
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import axios, { AxiosError, AxiosHeaders } from "axios";
|
|
2
|
-
import { HaloAuthenticationClient } from "../authentication/halo-authentication-client";
|
|
3
|
-
import { RelyingParty, XboxAuthenticationClient, } from "../authentication/xbox-authentication-client";
|
|
4
2
|
import { HaloCoreEndpoints } from "../endpoints/halo-core-endpoints";
|
|
3
|
+
import { AssetKind } from "../models/halo-infinite/asset-kind";
|
|
5
4
|
import { MatchType } from "../models/halo-infinite/match-type";
|
|
6
5
|
import { GlobalConstants } from "../util/global-contants";
|
|
7
|
-
import { AssetKind } from "../models/halo-infinite/asset-kind";
|
|
8
6
|
const assetKindUrlMap = {
|
|
9
7
|
[AssetKind.Map]: "Maps",
|
|
10
8
|
[AssetKind.UgcGameVariant]: "UgcGameVariants",
|
|
@@ -19,38 +17,19 @@ function wrapPlayerId(playerId) {
|
|
|
19
17
|
return `xuid(${playerId})`;
|
|
20
18
|
}
|
|
21
19
|
}
|
|
20
|
+
function unwrapPlayerId(playerId) {
|
|
21
|
+
const match = /^\w+\((\d+)\)$/.exec(playerId);
|
|
22
|
+
if (match) {
|
|
23
|
+
return match[1];
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
return playerId;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
22
29
|
export class HaloInfiniteClient {
|
|
23
|
-
|
|
24
|
-
constructor(
|
|
25
|
-
|
|
26
|
-
if (tokenPersister) {
|
|
27
|
-
return await tokenPersister.load("xbox.authToken");
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
}, async (token) => {
|
|
33
|
-
if (tokenPersister) {
|
|
34
|
-
await tokenPersister.save("xbox.authToken", token);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
this.haloAuthClient = new HaloAuthenticationClient(async () => {
|
|
38
|
-
const accessToken = await xboxAuthClient.getAccessToken();
|
|
39
|
-
const userToken = await xboxAuthClient.getUserToken(accessToken);
|
|
40
|
-
const xstsTicket = await xboxAuthClient.getXstsTicket(userToken, RelyingParty.Halo);
|
|
41
|
-
return xstsTicket.Token;
|
|
42
|
-
}, async () => {
|
|
43
|
-
if (tokenPersister) {
|
|
44
|
-
return await tokenPersister.load("halo.authToken");
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
}, async (token) => {
|
|
50
|
-
if (tokenPersister) {
|
|
51
|
-
await tokenPersister.save("halo.authToken", token);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
30
|
+
spartanTokenProvider;
|
|
31
|
+
constructor(spartanTokenProvider) {
|
|
32
|
+
this.spartanTokenProvider = spartanTokenProvider;
|
|
54
33
|
}
|
|
55
34
|
async executeRequest(url, method, useSpartanToken = true, useClearance = false, userAgent = GlobalConstants.HALO_WAYPOINT_USER_AGENT) {
|
|
56
35
|
const headers = new AxiosHeaders({
|
|
@@ -58,7 +37,7 @@ export class HaloInfiniteClient {
|
|
|
58
37
|
Accept: "application/json",
|
|
59
38
|
});
|
|
60
39
|
if (useSpartanToken) {
|
|
61
|
-
headers.set("x-343-authorization-spartan", await this.
|
|
40
|
+
headers.set("x-343-authorization-spartan", await this.spartanTokenProvider.getSpartanToken());
|
|
62
41
|
}
|
|
63
42
|
if (useClearance) {
|
|
64
43
|
throw new Error("TODO: Implement clearance");
|
|
@@ -94,6 +73,12 @@ export class HaloInfiniteClient {
|
|
|
94
73
|
* @param gamerTag - Gamertag to lookup.
|
|
95
74
|
*/
|
|
96
75
|
getUser = (gamerTag) => this.executeRequest(`https://${HaloCoreEndpoints.Profile}.${HaloCoreEndpoints.ServiceDomain}/users/gt(${gamerTag})`, "get");
|
|
76
|
+
/** Get gamertag info for several players.
|
|
77
|
+
* @param xuids - Xuids to lookup.
|
|
78
|
+
*/
|
|
79
|
+
getUsers = (xuids) => {
|
|
80
|
+
return this.executeRequest(`https://${HaloCoreEndpoints.Profile}.${HaloCoreEndpoints.ServiceDomain}/users?xuids=${xuids.map((x) => unwrapPlayerId(x)).join(",")}`, "get");
|
|
81
|
+
};
|
|
97
82
|
/** Get service record for a player.
|
|
98
83
|
* @param gamerTag - Gamertag to lookup.
|
|
99
84
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"halo-infinite-client.js","sourceRoot":"","sources":["../../src/core/halo-infinite-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,YAAY,EAAU,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"halo-infinite-client.js","sourceRoot":"","sources":["../../src/core/halo-infinite-client.ts"],"names":[],"mappings":"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"}
|