@xboxreplay/xboxlive-auth
Advanced tools
Comparing version 2.2.0 to 3.0.1
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -11,181 +12,11 @@ }); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const request = require("request"); | ||
const GitHubLinks = require("./github-links"); | ||
const errors = require("./errors"); | ||
const querystring_1 = require("querystring"); | ||
const CLIENT_ID = '0000000048093EE3'; | ||
const SCOPE = 'service::user.auth.xboxlive.com::MBI_SSL'; | ||
const RESPONSE_TYPE = 'token'; | ||
const DEFAULT_RELYING_PARTY = 'http://xboxlive.com'; | ||
const USER_AGENT = [ | ||
'Mozilla/5.0 (XboxReplay; XboxLiveAuth/2.0)', | ||
'AppleWebKit/537.36 (KHTML, like Gecko)', | ||
'Chrome/71.0.3578.98 Safari/537.36' | ||
].join(' '); | ||
const BASE_HEADERS = { | ||
Accept: 'application/json; charset=utf-8', | ||
'Accept-Language': 'en-US', | ||
'User-Agent': USER_AGENT | ||
}; | ||
const LIVE_ENDPOINTS = { | ||
authorize: 'https://login.live.com/oauth20_authorize.srf', | ||
redirect: 'https://login.live.com/oauth20_desktop.srf' | ||
}; | ||
const XBOX_LIVE_ENDPOINTS = { | ||
userAuthenticate: 'https://user.auth.xboxlive.com/user/authenticate', | ||
XSTSAuthorize: 'https://xsts.auth.xboxlive.com/xsts/authorize' | ||
}; | ||
const _getMatchForIndex = (entry, regex, index = 0) => { | ||
const match = entry.match(regex); | ||
if (match === null) | ||
return null; | ||
if (match[index] === void 0) | ||
return null; | ||
return match[index]; | ||
}; | ||
const _requiresIdentityConfirmation = (body) => { | ||
const m1 = _getMatchForIndex(body, /id=\"fmHF\" action=\"(.*?)\"/, 1); | ||
const m2 = _getMatchForIndex(m1 || '', /identity\/confirm/, 0); | ||
return m2 !== null; | ||
}; | ||
const _preAuth = () => new Promise((resolve, reject) => { | ||
const jar = request.jar(); | ||
const authorizeQuery = { | ||
client_id: CLIENT_ID, | ||
redirect_uri: LIVE_ENDPOINTS.redirect, | ||
response_type: RESPONSE_TYPE, | ||
scope: SCOPE, | ||
display: 'touch', | ||
locale: 'en' | ||
}; | ||
request({ | ||
uri: LIVE_ENDPOINTS.authorize + | ||
'?' + | ||
unescape(querystring_1.stringify(authorizeQuery)), | ||
gzip: true, | ||
headers: BASE_HEADERS, | ||
jar | ||
}, (err, _, body) => { | ||
if (err) | ||
return reject(errors.internal(err.message)); | ||
const matches = { | ||
PPFT: _getMatchForIndex(body, /sFTTag:'.*value=\"(.*)\"\/>'/, 1), | ||
urlPost: _getMatchForIndex(body, /urlPost:'([A-Za-z0-9:\?_\-\.&\\/=]+)/, 1) | ||
}; | ||
if (matches.PPFT === null) { | ||
return reject(errors.matchError(`Could not match "PPFT" parameter, please fill an issue on ${GitHubLinks.createIssue}`)); | ||
} | ||
else if (matches.urlPost === null) { | ||
return reject(errors.matchError(`Could not match "urlPost" parameter, please fill an issue on ${GitHubLinks.createIssue}`)); | ||
} | ||
return resolve({ | ||
jar, | ||
matches: { | ||
PPFT: matches.PPFT, | ||
urlPost: matches.urlPost | ||
} | ||
}); | ||
}); | ||
const live_1 = require("./core/live"); | ||
const xboxlive_1 = require("./core/xboxlive"); | ||
exports.exchangeRpsTicketForUserToken = xboxlive_1.exchangeRpsTicketForUserToken; | ||
exports.exchangeUserTokenForXSTSIdentity = xboxlive_1.exchangeUserTokenForXSTSIdentity; | ||
exports.authenticate = (email, password, options = {}) => __awaiter(void 0, void 0, void 0, function* () { | ||
const preAuthResponse = yield live_1.preAuth(); | ||
const logUserResponse = yield live_1.logUser(preAuthResponse, { email, password }); | ||
const exchangeRpsTicketForUserTokenResponse = yield xboxlive_1.exchangeRpsTicketForUserToken(logUserResponse.access_token); | ||
return xboxlive_1.exchangeUserTokenForXSTSIdentity(exchangeRpsTicketForUserTokenResponse.Token, options.XSTSRelyingParty, false); | ||
}); | ||
const _logUser = (preAuthResponse, credentials) => new Promise((resolve, reject) => { | ||
const jar = request.jar(); | ||
request({ | ||
uri: preAuthResponse.matches.urlPost, | ||
method: 'POST', | ||
gzip: true, | ||
followRedirect: false, | ||
headers: Object.assign({}, BASE_HEADERS, { 'Content-Type': 'application/x-www-form-urlencoded', Cookie: preAuthResponse.jar.getCookieString(LIVE_ENDPOINTS.authorize) }), | ||
body: querystring_1.stringify({ | ||
login: credentials.email, | ||
loginfmt: credentials.email, | ||
passwd: credentials.password, | ||
PPFT: preAuthResponse.matches.PPFT | ||
}), | ||
jar | ||
}, (err, response, body) => { | ||
if (err) | ||
return reject(errors.internal(err.message)); | ||
const { location } = response.headers; | ||
if (location === void 0) { | ||
return _requiresIdentityConfirmation(body) | ||
? reject(errors.unauthorizedActivity()) | ||
: reject(errors.invalidCredentials()); | ||
} | ||
const matches = { | ||
accessToken: _getMatchForIndex(location, /access_token=(.+?)&/, 1), | ||
refreshToken: _getMatchForIndex(location, /refresh_token=(.+?)&/, 1) | ||
}; | ||
if (matches.accessToken === null) { | ||
return reject(errors.matchError(`Could not match "access_token" parameter, please fill an issue on ${GitHubLinks.createIssue}`)); | ||
} | ||
return resolve({ | ||
accessToken: matches.accessToken, | ||
refreshToken: matches.refreshToken | ||
}); | ||
}); | ||
}); | ||
exports.exchangeRpsTicketForUserToken = (RpsTicket) => new Promise((resolve, reject) => { | ||
request({ | ||
uri: XBOX_LIVE_ENDPOINTS.userAuthenticate, | ||
method: 'POST', | ||
gzip: true, | ||
headers: Object.assign({}, BASE_HEADERS, { 'x-xbl-contract-version': 0 }), | ||
json: { | ||
RelyingParty: 'http://auth.xboxlive.com', | ||
TokenType: 'JWT', | ||
Properties: { | ||
AuthMethod: 'RPS', | ||
SiteName: 'user.auth.xboxlive.com', | ||
RpsTicket | ||
} | ||
} | ||
}, (err, response, body) => { | ||
if (err) | ||
return reject(errors.internal(err.message)); | ||
else if (response.statusCode !== 200) | ||
return reject(errors.exchangeFailure('Could not exchange specified "RpsTicket"')); | ||
return resolve(body.Token); | ||
}); | ||
}); | ||
exports.exchangeAccessTokenForUserToken = (accessToken) => exports.exchangeRpsTicketForUserToken(accessToken); | ||
exports.exchangeUserTokenForXSTSIdentity = (userToken, XSTSRelyingParty = DEFAULT_RELYING_PARTY) => new Promise((resolve, reject) => { | ||
request({ | ||
uri: XBOX_LIVE_ENDPOINTS.XSTSAuthorize, | ||
method: 'POST', | ||
gzip: true, | ||
headers: Object.assign({}, BASE_HEADERS, { 'x-xbl-contract-version': 0 }), | ||
json: { | ||
RelyingParty: XSTSRelyingParty, | ||
TokenType: 'JWT', | ||
Properties: { | ||
UserTokens: [userToken], | ||
SandboxId: 'RETAIL' | ||
} | ||
} | ||
}, (err, response, body) => { | ||
if (err) | ||
return reject(errors.internal(err.message)); | ||
else if (response.statusCode !== 200) { | ||
const isDefaultRelyingParty = XSTSRelyingParty === DEFAULT_RELYING_PARTY; | ||
const computedErrorMessage = [ | ||
'Could not exchange "userToken", please', | ||
`refer to ${GitHubLinks.seeUserTokenIssue}` | ||
]; | ||
if (isDefaultRelyingParty === false) | ||
computedErrorMessage.splice(1, 0, 'double check the specified "XSTSRelyingParty" or'); | ||
return reject(errors.exchangeFailure(computedErrorMessage.join(' '))); | ||
} | ||
return resolve({ | ||
userXUID: body.DisplayClaims.xui[0].xid || null, | ||
userHash: String(body.DisplayClaims.xui[0].uhs), | ||
XSTSToken: String(body.Token), | ||
expiresOn: String(body.NotAfter) | ||
}); | ||
}); | ||
}); | ||
exports.authenticate = (email, password, options = {}) => __awaiter(this, void 0, void 0, function* () { | ||
const preAuthResponse = yield _preAuth(); | ||
const logUser = yield _logUser(preAuthResponse, { email, password }); | ||
const userToken = yield exports.exchangeRpsTicketForUserToken(logUser.accessToken); | ||
return exports.exchangeUserTokenForXSTSIdentity(userToken, options.XSTSRelyingParty); | ||
}); |
{ | ||
"name": "@xboxreplay/xboxlive-auth", | ||
"description": "Simple Xbox Live authentication module.", | ||
"version": "2.2.0", | ||
"version": "3.0.1", | ||
"keywords": [ | ||
@@ -10,2 +10,7 @@ "xboxreplay", | ||
], | ||
"license": "MIT", | ||
"author": { | ||
"name": "Alexis Bize", | ||
"email": "alexis.bize@gmail.com" | ||
}, | ||
"repository": { | ||
@@ -15,43 +20,19 @@ "type": "git", | ||
}, | ||
"license": "MIT", | ||
"types": "./index.d.ts", | ||
"main": "./dist/index.js", | ||
"author": { | ||
"name": "Alexis Bize", | ||
"email": "alexis.bize@gmail.com" | ||
}, | ||
"types": "./dist/index.ts", | ||
"scripts": { | ||
"build": "npm run clean && ./node_modules/.bin/tsc", | ||
"build": "npm run clean && ./node_modules/.bin/tsc && rm -rf ./dist/__tests__", | ||
"clean": "rm -rf ./dist", | ||
"prepublishOnly": "npm run test && npm run build", | ||
"test": " ./node_modules/.bin/jest --runInBand", | ||
"watch": "npm run clean && ./node_modules/.bin/tsc-watch" | ||
"test": "ts-node ./__tests__/e2e.test.js" | ||
}, | ||
"dependencies": { | ||
"@xboxreplay/errors": "^0.1.0", | ||
"request": "^2.88.0" | ||
"axios": "^0.19.2" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^24.0.15", | ||
"@types/node": "^12.0.10", | ||
"@types/request": "^2.48.1", | ||
"tsc-watch": "^2.2.1", | ||
"typescript": "^3.5.2", | ||
"jest": "^24.8.0", | ||
"ts-jest": "^24.0.2" | ||
}, | ||
"jest": { | ||
"roots": [ | ||
"<rootDir>/src" | ||
], | ||
"transform": { | ||
"^.+\\.tsx?$": "ts-jest" | ||
}, | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js" | ||
], | ||
"testRegex": "__tests__/.*\\.(ts|tsx|js)$" | ||
"@types/node": "^13.11.1", | ||
"ts-node": "^8.8.2", | ||
"typescript": "^3.8.3" | ||
} | ||
} |
@@ -10,17 +10,2 @@ # Xbox Live - Auth | ||
### Clone | ||
``` | ||
$ git clone https://github.com/XboxReplay/xboxlive-auth.git | ||
``` | ||
### Build | ||
``` | ||
$ npm run build | ||
``` | ||
### Test | ||
``` | ||
$ npm run test | ||
``` | ||
### Usage example | ||
@@ -31,3 +16,3 @@ | ||
XboxLiveAuth.authenticate('xbl-account@domain.com', '*********') | ||
XboxLiveAuth.authenticate('xbl-account@your-domain.com', '*********') | ||
.then(console.info) | ||
@@ -41,3 +26,3 @@ .catch(console.error); | ||
"userHash": "1890318589445465111", | ||
"XSTSToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.iMrN7XT_jCcRXWKwUo_JPWeRO75dBOGTzerAO", | ||
"XSTSToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiWGJveFJlcGxheS5uZXQifQ.c2UraxPmZ4STYozrjFEW8SBqU0WjnIV0h-jjnfsKtrA", | ||
"expiresOn": "2019-04-05T05:43:32.6275675Z" | ||
@@ -56,3 +41,3 @@ } | ||
The best way to interact with the API is to use our [XboxLive-API](https://github.com/XboxReplay/xboxlive-api) module which has the **XboxLive-Auth** as a peer dependency. That said, a cURL example is available below. | ||
The best way to interact with the API is to use our [XboxLive-API](https://github.com/XboxReplay/xboxlive-api) module. That said, a cURL example is available below. | ||
@@ -72,8 +57,8 @@ **Sample call:** | ||
{ | ||
"id": "2535465515082324", | ||
"hostId": "2535465515082324", | ||
"id": "2500000000000000", | ||
"hostId": "2500000000000000", | ||
"settings": [ | ||
{ | ||
"id": "Gamerscore", | ||
"value": "6270" | ||
"value": "1000000" | ||
} | ||
@@ -89,3 +74,3 @@ ], | ||
The "XSTSRelyingParty" is a domain configured by Microsoft and / or its partners to create a XSTS token which is intended to be used for a targeted service. For instance, if you use `http://beam.pro/` you will be able to interact with the private **Mixer.com** API. A partial list can be found here: https://title.mgt.xboxlive.com/titles/default/endpoints?type=4. | ||
The "XSTSRelyingParty" is a domain configured by Microsoft and / or its partners to create a XSTS token which is intended to be used for a targeted service. For instance, if you use `http://beam.pro/` you will be able to interact with the private **Mixer.com** API. A partial list can be found here: https://title.mgt.xboxlive.com/titles/default/endpoints?type=1. | ||
@@ -92,0 +77,0 @@ ### What about 2FA (Two-factor authentication)? |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3
15
17284
329
78
1
+ Addedaxios@^0.19.2
+ Addedaxios@0.19.2(transitive)
+ Addedfollow-redirects@1.5.10(transitive)
- Removedrequest@^2.88.0
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpsl@1.9.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)