diff --git a/src/index.js b/src/index.js
index 56c4a4a..829b51a 100644
--- a/src/index.js
+++ b/src/index.js
@@ -3,7 +3,6 @@
import Promise from 'bluebird'
import assert from 'assert'
import utils from './lib/utils'
-import Login from './lib/login'
import MobileLogin from './lib/mobile-login'
import _ from 'underscore'
import Methods from './lib/methods'
@@ -55,13 +54,7 @@ let Fut = class Fut extends Methods {
this.isReady = false // instance will be ready after we called _init func
Object.assign(this.options, defaultOptions, options)
- if (this.options.loginType === 'web') {
- this.loginLib = Promise.promisifyAll(new Login({proxy: options.proxy}))
- } else if (this.options.loginType === 'mobile') {
- this.loginLib = new MobileLogin({...options, tfCodeHandler: options.tfAuthHandler})
- } else {
- throw new Error(`Unknown loginType ${this.options.loginType}`)
- }
+ this.loginLib = new MobileLogin({...options, tfCodeHandler: options.tfAuthHandler})
}
async loadVariable (key) {
@@ -86,15 +79,13 @@ let Fut = class Fut extends Methods {
async login () {
await this._init()
- const loginMethod = this.options.loginType === 'web' ? 'loginAsync' : 'login'
+ const loginMethod = 'login'
const loginResponse = await this.loginLib[loginMethod](this.options.email, this.options.password, this.options.secret, this.options.platform, this.options.tfAuthHandler, this.options.captchaHandler)
-
await this.saveVariable('cookie', this.loginLib.getCookieJarJSON())
this.rawApi = loginResponse.apiRequest
const loginDefaults = _.omit(this.loginLib.getLoginDefaults(), 'jar')
await this.saveVariable('loginDefaults', loginDefaults)
- if (this.options.loginType === 'web') this.rawApi = Promise.promisify(this.rawApi, this)
this.isReady = true
const user = await this.getUser()
if (user.userInfo.feature.trade === 0) {
diff --git a/src/lib/login.js b/src/lib/login.js
deleted file mode 100644
index 5a6fe8e..0000000
--- a/src/lib/login.js
+++ /dev/null
@@ -1,490 +0,0 @@
-'use strict'
-
-module.exports = function (options) {
- var __ = require('underscore')
- var request = require('request')
- var hasher = require('./eaHasher')
- var urls = require('./urls')()
- var CookieJar = require('tough-cookie').CookieJar
- var utils = require('./utils')
- const lodash = require('lodash')
-
- var defaultRequest = null
-
- var loginDetails = {}
-
- var loginResponse = {
- nucleusId: null,
- shardInfos: null,
- shard: null,
- persona: null,
- sessionData: null,
- apiRequest: null
- }
-
- var jar = request.jar()
-
- var loginDefaults = {}
-
- var Login = function () {}
-
- Login.prototype.login = function (email, password, secret, platform, tfCodeCb, captchaCb, loginCb, version = 17) {
- Login.version = version
-
- if (!email || !__.isString(email) || email.trim().length <= 0) return loginCb(new Error('Email is empty.'))
-
- if (!password || !__.isString(password) || password.trim().length <= 0) return loginCb(new Error('Password is empty.'))
-
- if (!secret || !__.isString(secret) || email.trim().length <= 0) return loginCb(new Error('Secret is empty.'))
-
- if (!platform || !__.isString(platform) || platform.trim().length <= 0) return loginCb(new Error('Platform is empty.'))
- if (!getPlatform(platform)) return loginCb(new Error('Platform is invalid.'))
-
- if (!__.isFunction(tfCodeCb)) return loginCb(new Error('tfCodeCb is not a function.'))
-
- if (!__.isFunction(captchaCb)) return loginCb(new Error('captchaCb is not a function.'))
-
- if (!__.isFunction(loginCb)) return loginCb(new Error('loginCb is not a function.'))
-
- loginDetails = {
- 'email': email,
- 'password': password,
- 'secret': hasher(secret),
- 'tfCodeCb': tfCodeCb,
- 'loginCb': loginCb,
- 'gameSku': getGameSku(platform, version),
- 'platform': getPlatform(platform),
- captchaCb: captchaCb
- }
-
- let requestConfigObj = {
- jar: jar,
- followAllRedirects: true,
- gzip: true,
- headers: {
- 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36',
- 'Accept': 'text/html, application/xhtml+xml, */*',
- 'Accept-Encoding': 'gzip, deflate',
- 'Accept-Language': 'en-US,en;q=0.8',
- 'Connection': 'keep-alive',
- 'DNT': '1',
- 'Cache-Control': 'no-cache'
- }
- }
-
- if (options.proxy) {
- requestConfigObj.proxy = options.proxy
- }
-
- defaultRequest = request.defaults(requestConfigObj)
- lodash.merge(loginDefaults, requestConfigObj)
-
- getMain()
- }
-
- Login.prototype.getCookieJarJSON = function () {
- return jar._jar.serializeSync()
- }
-
- Login.prototype.setCookieJarJSON = function (json) {
- jar._jar = CookieJar.deserializeSync(json)
- }
-
- Login.prototype.getLoginDefaults = function () {
- return loginDefaults
- }
-
- Login.prototype.getCaptcha = function (cb) {
- const url = urls.login.getCaptcha + new Date().getTime()
- defaultRequest.get(url, function (error, response, body) {
- if (error) return cb(error)
- if (response.statusCode !== 200) return cb(new Error(`Captcha error ${response.statusCode} ${body}`))
- cb(body)
- })
- }
-
- function getGameSku (platform, version) {
- switch (platform) {
- case 'pc':
- return `FFA${version}PCC`
- case 'ps3':
- return `FFA${version}PS3`
- case 'ps4':
- return `FFA${version}PS4`
- case 'x360':
- return `FFA${version}XBX`
- case 'xone':
- return `FFA${version}XBO`
- }
-
- return null
- }
-
- function getPlatform (platform) {
- switch (platform) {
- case 'pc':
- return 'pc'
- case 'ps3':
- case 'ps4':
- return 'ps3'
- case 'x360':
- case 'xone':
- return '360'
- }
- return null
- }
-
- function getMain () {
- defaultRequest.get(urls.login.main, { maxRedirects: 20 }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (body.indexOf('
FIFA Football | Football Club | EA SPORTS') > 0) return getNucleus()
-
- if (body.indexOf('FIFA Football | FUT Web App | EA SPORTS') > 0) return getNucleus()
-
- if (body.indexOf('Log In') > 0) return loginForm(response.request.href)
-
- loginDetails.loginCb(new Error('Unknown response. Unable to login.'))
- })
- }
-
- function loginForm (url) {
- defaultRequest.post(url, {
- form: {
- 'email': loginDetails.email,
- 'password': loginDetails.password,
- 'country': 'US', // is it important?
- 'phoneNumber': '', // TODO: add phone code verification
- 'passwordForPhone': '',
- 'gCaptchaResponse': '',
- 'isPhoneNumberLogin': 'false', // TODO: add phone login
- 'isIncompletePhone': '',
- '_rememberMe': 'on',
- 'rememberMe': 'on',
- '_eventId': 'submit'
- }
- }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (body.indexOf('var redirectUri') > 0) return handleRedirect(body)
-
- if (body.indexOf('FIFA Football | FUT Web App | EA SPORTS') > 0) return getNucleus()
-
- if (body.indexOf('Log In') > 0) return loginDetails.loginCb(new Error('Unable to log in.'))
-
- if (body.indexOf('Set Up an App Authenticator') > 0) return cancelLoginVerificationUpdate(response.request.href)
-
- if (body.indexOf('Account Update') > 0) return acceptAccountUpdate(response.request.href)
-
- if (body.indexOf('Login Verification') > 0) {
- loginDetails.tfCodeCb().then((tfCode) => sendTwoFactorCode(response.request.href, tfCode))
- return
- }
- loginDetails.loginCb(new Error(JSON.stringify(response, null, 2)))
- })
- }
-
- function handleRedirect (body) {
- var url = body.match(/var redirectUri = '(https?:\/\/.+\/p\/web[0-9]+\/login\?execution=.+?)'/)
- defaultRequest.get(url[1] + '&_eventId=end', function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (body.indexOf('FIFA Football | FUT Web App | EA SPORTS') > 0) return getNucleus()
-
- if (body.indexOf('Log In') > 0) return loginDetails.loginCb(new Error('Unable to log in.'))
-
- if (body.indexOf('Set Up an App Authenticator') > 0) return cancelLoginVerificationUpdate(response.request.href)
-
- if (body.indexOf('Account Update') > 0) return acceptAccountUpdate(response.request.href)
-
- if (body.indexOf('Login Verification') > 0) {
- loginDetails.tfCodeCb().then((tfCode) => sendTwoFactorCode(response.request.href, tfCode))
- return
- }
- loginDetails.loginCb(new Error(JSON.stringify(response, null, 2)))
- })
- }
-
- function sendTwoFactorCode (url, tfCode) {
- defaultRequest.post(url, {
- form: {
- 'twofactorCode': tfCode,
- 'twoFactorCode': tfCode,
- '_eventId': 'submit',
- '_trustThisDevice': 'on',
- 'trustThisDevice': 'on'
- }
- }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (body.indexOf('FIFA Football | FUT Web App | EA SPORTS') > 0) return getNucleus()
-
- if (body.indexOf('Set Up an App Authenticator') > 0) return cancelLoginVerificationUpdate(response.request.href)
-
- if (body.indexOf('Login Verification') > 0) return loginDetails.loginCb(new Error('Wrong two factor code.'))
-
- loginDetails.loginCb(new Error('Unknown response. Unable to login.'))
- })
- }
-
- function acceptAccountUpdate (url) {
- defaultRequest.post(url, {
- form: {
- '_eventId': 'submit'
- }
- }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (body.indexOf('Login Verification') > 0) return chooseEmailSending(response.request.href)
-
- loginDetails.loginCb(new Error('Unknown response. Unable to login. At acceptAccountUpdate'))
- })
- }
-
- function chooseEmailSending (url) {
- defaultRequest.post(url, {
- form: {
- tfa_type: '',
- twofactorType: 'EMAIL',
- country: 0,
- phoneNumber: '',
- _eventId: 'submit',
- appleDevice: 'IPHONE'
- }
- }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (body.indexOf('Login Verification') > 0) {
- loginDetails.tfCodeCb().then((tfCode) => sendTwoFactorCode(response.request.href, tfCode))
- return
- }
-
- loginDetails.loginCb(new Error('Unknown response. Unable to login. At chooseEmailSending'))
- })
- }
-
- function cancelLoginVerificationUpdate (url) {
- defaultRequest.post(url, {
- form: {
- '_eventId': 'cancel',
- 'appDevice': 'IPHONE'
- }
- }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (body.indexOf('FIFA Football | FUT Web App | EA SPORTS') > 0) return getNucleus()
-
- loginDetails.loginCb(new Error('Unknown response. Unable to login.'))
- })
- }
-
- function getNucleus () {
- defaultRequest.get(urls.login.nucleus, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- var match = body.match(/EASW_ID\W*=\W*'(\d*)'/)
- if (match === null || match[1] === null) return loginDetails.loginCb(new Error("Unable to get the 'EASW_ID'. Unable to login."))
-
- loginResponse.nucleusId = match[1]
-
- getShards()
- })
- }
-
- function getShards () {
- let requestConfigObj = {
- json: true,
- headers: {
- 'Easw-Session-Data-Nucleus-Id': loginResponse.nucleusId,
- 'X-UT-Embed-Error': true,
- 'X-UT-Route': 'https://utas.external.fut.ea.com',
- 'X-Requested-With': 'XMLHttpRequest',
- 'Referer': urls.referer
- }
- }
-
- defaultRequest = defaultRequest.defaults(requestConfigObj)
- lodash.merge(loginDefaults, requestConfigObj)
-
- defaultRequest.get(urls.login.shards, function (error, responsse, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (!body || !body.shardInfo) return loginDetails.loginCb(new Error('Unable to get shards. Unable to login.'))
-
- loginResponse.shardInfos = body.shardInfo
-
- getAccount()
- })
- }
-
- function getAccount () {
- loginResponse.shard = __.find(loginResponse.shardInfos, function (si) {
- return si.skus.indexOf(loginDetails.gameSku) >= 0
- })
-
- if (!loginResponse.shard) return loginDetails.loginCb(new Error('Unable to find shardInfo.'))
-
- let requestConfigObj = {
- headers: {
- 'X-UT-Route': 'https://' + loginResponse.shard.clientFacingIpPort
- }
- }
-
- defaultRequest = defaultRequest.defaults(requestConfigObj)
- lodash.merge(loginDefaults, requestConfigObj)
-
- defaultRequest.get(urls.login.accounts, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (!body.userAccountInfo) return loginDetails.loginCb(new Error('Unable to get account infos.'))
-
- loginResponse.persona = __.find(body.userAccountInfo.personas,
- function (persona) {
- return __.some(persona.userClubList, function (userClub) {
- return userClub.platform === loginDetails.platform
- })
- })
-
- if (!loginResponse.persona) return loginDetails.loginCb(new Error('Unable to get account info persona.'))
-
- getSession()
- })
- }
-
- function getSession () {
- var data = {
- 'isReadOnly': false,
- 'sku': `FUT${Login.version}WEB`,
- 'clientVersion': 1,
- 'nucleusPersonaId': loginResponse.persona.personaId,
- 'nucleusPersonaDisplayName': loginResponse.persona.personaName,
- 'gameSku': loginDetails.gameSku,
- 'nucleusPersonaPlatform': getPlatform(loginDetails.platform),
- 'locale': 'en-GB',
- 'method': 'authcode',
- 'priorityLevel': 4,
- 'identification': {'authCode': ''}
- }
-
- defaultRequest.post(urls.login.session, { body: data, qs: { 'sku_a': `F${Login.version}` } }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
- if (response.statusCode !== 200) return loginDetails.loginCb(new Error(`Unknown response. Unable to login. ${response.statusCode} ${JSON.stringify(body)}`))
-
- loginResponse.sessionData = body
-
- if (loginResponse.sessionData.sid) return phishing()
-
- loginDetails.loginCb(new Error(`Unknown response. Unable to login. ${response.statusCode} ${JSON.stringify(body)}`))
- })
- }
-
- function phishing () {
- let requestConfigObj = {
- headers: {
- 'X-UT-SID': loginResponse.sessionData.sid
- }
- }
- defaultRequest = defaultRequest.defaults(requestConfigObj)
- lodash.merge(loginDefaults, requestConfigObj)
-
- defaultRequest.get(urls.login.question, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (utils.isApiMessage(body) && body.token) {
- loginResponse.token = body.token
- let requestConfigObj = {
- baseUrl: 'https://' + loginResponse.sessionData.ipPort.split(':')[0],
- headers: {
- 'X-UT-PHISHING-TOKEN': loginResponse.token,
- 'X-HTTP-Method-Override': 'GET',
- 'X-UT-Route': 'https://' + loginResponse.sessionData.ipPort.split(':')[0],
- 'x-flash-version': '20,0,0,272'
- }
- }
- loginResponse.apiRequest = defaultRequest.defaults(requestConfigObj)
- lodash.merge(loginDefaults, requestConfigObj)
-
- return loginDetails.loginCb(null, loginResponse)
- }
-
- if (body.question) return validate()
- else if (body.code === '459') {
- // validate captcha
- // then do the phishing() again
- getCaptcha((err, rawCaptcha) => {
- if (err) loginDetails.loginCb(err)
- loginDetails.captchaCb(rawCaptcha, (captcha) => {
- validateCaptcha(captcha, (err) => {
- if (err) loginDetails.loginCb(err)
- return phishing()
- })
- })
- })
- } else {
- let error = new Error(`Unknown response. Unable to login. response: ${JSON.stringify(body)}`)
- error.futLoginError = body
- loginDetails.loginCb(error)
- }
- })
- }
-
- function getCaptcha (cb) {
- const url = urls.login.captchaImg + new Date().getTime()
- defaultRequest.get({
- url,
- encoding: null
- }, function (error, response, body) {
- if (error) return cb(error)
- if (response.statusCode !== 200) return cb(new Error(`Captcha error ${response.statusCode} ${body}`))
- cb(null, body)
- })
- }
-
- function validateCaptcha (captcha, cb) {
- const url = urls.login.validateCaptcha
- defaultRequest.post(url, {
- json: true,
- body: {
- 'token': 'AAAA',
- 'answer': captcha
- }
- }, (error, response, body) => {
- if (error) return cb(error)
- if (response.statusCode !== 200) return cb(new Error(`Captcha is not ok ${response.statusCode} ${body}`))
- cb()
- })
- }
-
- function validate () {
- defaultRequest.post(urls.login.validate, {
- form: { answer: loginDetails.secret }
- }, function (error, response, body) {
- if (error) return loginDetails.loginCb(error)
-
- if (!body) return loginDetails.loginCb(new Error('Unknown response. Unable to login.'))
-
- if (body.string !== 'OK') return loginDetails.loginCb(new Error('Wrong secret. Unable to login.'))
-
- if (body.string === 'OK') loginResponse.token = body.token
-
- if (!loginResponse.token) return loginDetails.loginCb(new Error('Unknown response. Unable to login.'))
-
- let requestConfigObj = {
- baseUrl: 'https://' + loginResponse.sessionData.ipPort.split(':')[0],
- headers: {
- 'X-UT-PHISHING-TOKEN': loginResponse.token,
- 'X-HTTP-Method-Override': 'GET',
- 'X-UT-Route': 'https://' + loginResponse.sessionData.ipPort.split(':')[0],
- 'x-flash-version': '20,0,0,272',
- 'Accept': 'application/json'
- }
- }
- loginResponse.apiRequest = defaultRequest.defaults(requestConfigObj)
- lodash.merge(loginDefaults, requestConfigObj)
-
- loginDetails.loginCb(null, loginResponse)
- })
- }
-
- return new Login()
-}
diff --git a/src/lib/mobile-login.js b/src/lib/mobile-login.js
index 29e421d..54d0b4b 100644
--- a/src/lib/mobile-login.js
+++ b/src/lib/mobile-login.js
@@ -8,8 +8,6 @@ import eaHasher from './eaHasher'
import {CookieJar} from 'tough-cookie'
import lodash from 'lodash'
-const crypto = Promise.promisifyAll(require('crypto'))
-
export default class MobileLogin {
jar = request.jar()
loginDefaults = {}
@@ -18,10 +16,7 @@ export default class MobileLogin {
* [constructor description]
* @param {[type]} options.email [description]
* @param {[type]} options.password [description]
- * @param {[type]} options.secret [description]
* @param {[type]} options.platform [description]
- * @param {[type]} options.captchaHandler [description]
- * @param {[type]} options.tfCodeHandler [description]
* @param {[String]} options.proxy [description]
* @return {[type]} [description]
*/
@@ -83,9 +78,7 @@ export default class MobileLogin {
}
async getLogin () {
- // We will use machine key later at getNucleusCode
- this.machineKey = await generateMachineKey()
- const url = 'https://accounts.ea.com/connect/auth?client_id=FIFA-16-MOBILE-COMPANION&response_type=code&display=web2/login&scope=basic.identity+offline+signin&locale=en_US&prompt=login&machineProfileKey=' + this.machineKey
+ const url = 'https://accounts.ea.com/connect/auth?prompt=login&accessToken=&client_id=FIFA-18-WEBCLIENT&response_type=token&display=web2/login&locale=en_US&redirect_uri=https://www.easports.com/fifa/ultimate-team/web-app/auth.html&scope=basic.identity+offline+signin'
const response = await this.defaultRequest.getAsync(url)
const title = getTitle(response)
@@ -99,7 +92,7 @@ export default class MobileLogin {
const form = {
email: this.options.email,
password: this.options.password,
- country: 'HU',
+ country: 'US',
phoneNumber: '',
passwordForPhone: '',
_rememberMe: 'on',
@@ -116,49 +109,62 @@ export default class MobileLogin {
if (!response.body.includes('redirectUri')) {
throw new Error(`Unknow response at 'postLogin' title was: ${title}`)
}
- return this.postLoginRedirect(response)
+ return await this.postLoginRedirect(response)
}
async postLoginRedirect (prevResponse) {
- const urlRegex = new RegExp("var redirectUri = '(.*)'")
- const qsRegex = /redirectUri = redirectUri \+ "(.*)";/
+ const urlRegex = new RegExp(/(https?:\/\/(www\/.)?[-a-zA-Z0-9@:%._\/+~#=]{2,256}\/.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\/+.~#?&//=]*))/gm)
let nextUrl
try {
- nextUrl = urlRegex.exec(prevResponse.body)[1]
- nextUrl += qsRegex.exec(prevResponse.body)[1]
+ nextUrl = urlRegex.exec(prevResponse.body)[0]
} catch (e) {
throw new Error(`RegExp failed at 'postLogin' body was: ${prevResponse.body}`)
}
const response = await this.defaultRequest.getAsync(nextUrl)
- const title = getTitle(response)
- if (title === 'Login Verification') return this.handleTwoFactorCode(response.request.href)
- else if (response.request.href.includes('code=')) {
- try {
- let code = urlModule.parse(response.request.href, true).query.code
- return this.wtfLogin(code)
- } catch (e) {
- throw new Error(`Couldn't parse code from url at postLoginRedirect: ${e.message}`)
+ if (response.body.indexOf('Your credentials are incorrect') !== -1) {
+ throw new Error('Unable to login. Wrong email or password ?')
+ }
+
+ return await this.sendEnd(response)
+ }
+
+ async sendEnd (prevResponse) {
+ let url = prevResponse.request.href + '&_eventId=end'
+
+ const response = await this.defaultRequest.getAsync(url)
+ if (response.body.indexOf('Login Verification') !== -1) {
+ if (response.body.indexOf('In order to verify your identity') !== -1) {
+ const form = {
+ codeType: 'APP',
+ _eventId: 'submit'
+ }
+ const response2 = await this.defaultRequest.postAsync(response.request.href, {form})
+
+ if (response2.body.indexOf('Login Verification') !== -1) {
+ await this.handleTwoFactorCode(response2.request.href)
+ }
+
+ await this.wtfLogin()
+
+ return response2.request.href
}
}
- throw Error(`Unknow response at 'postLoginRedirect' title was: ${title}`)
+
+ await this.wtfLogin()
}
async handleTwoFactorCode (url) {
const tfCode = await this.options.tfCodeHandler()
const form = {
- twofactorCode: tfCode,
+ oneTimeCode: tfCode,
trustThisDevice: 'on',
+ _trustThisDevice: 'on',
_eventId: 'submit'
}
const response = await this.defaultRequest.postAsync(url, {form})
- const title = getTitle(response)
-
- if (title === 'Set Up an App Authenticator') return this.cancelLoginVerificationUpdate(response.request.href)
- if (title === 'Login Verification') throw new Error('Wrong two factor code.')
-
- throw Error(`Unknow response at 'handleTwoFactorCode' title was: ${title}`)
+ if (response.body.indexOf('Login Verification') !== -1) throw new Error('Wrong two factor code.')
}
async cancelLoginVerificationUpdate (url) {
@@ -180,27 +186,22 @@ export default class MobileLogin {
return true
}
})
- return this.wtfLogin(code)
+ return await this.wtfLogin(code)
}
- async wtfLogin (code) {
- const postUrl = `https://accounts.ea.com/connect/token?grant_type=authorization_code&code=${code}&client_id=FIFA-16-MOBILE-COMPANION&client_secret=KrEoFK9ssvXKRWnTMgAu1OAMn7Y37ueUh1Vy7dIk2earFDUDABCvZuNIidYxxNbhwbj3y8pq6pSf8zBW`
- let response = await this.defaultRequest.postAsync(postUrl, {json: true, headers: {'content-type': 'application/x-www-form-urlencoded'}})
- let token = response.body.access_token
+ async wtfLogin () {
+ var url = 'https://accounts.ea.com/connect/auth?response_type=token&redirect_uri=nucleus%3Arest&prompt=none&client_id=ORIGIN_JS_SDK'
+ let response = await this.defaultRequest.getAsync(url)
+ let token = JSON.parse(response.body).access_token
assert(token, 'Failed to get access token at `wtfLogin`')
- // this stuff seems useless but let's just do it
- const url1 = `https://signin.ea.com/p/mobile/fifa/companion/code?code=${code}`
- await this.defaultRequest.getAsync(url1)
-
const nucleusUserId = await this.getPid(token)
- const sidCode = await this.getSidCode(token)
+ // const sidCode = await this.getSidCode(token)
const sidCode2 = await this.getSidCode(token)
// We will get the api url after shards
await this.getShards()
- await this.getUserAccounts(nucleusUserId)
- const powSessionId = await this.getPowSid(sidCode)
- const nucleusPersonaId = await this.getNucleusPersonaId(nucleusUserId, powSessionId)
+ let userAccounts = await this.getUserAccounts(nucleusUserId)
+ const nucleusPersonaId = await this.getNucleusPersonaId(userAccounts.body.userAccountInfo.personas)
const sid = await this.getSid(sidCode2, nucleusPersonaId)
const requestConfigObj1 = {
@@ -214,7 +215,7 @@ export default class MobileLogin {
lodash.merge(this.loginDefaults, requestConfigObj1)
this.api = Promise.promisifyAll(this.defaultRequest.defaults(requestConfigObj1))
- const phisingToken = await this.validate()
+ const phisingToken = await this.validate(sid)
const requestConfigObj2 = {
headers: {
@@ -263,29 +264,23 @@ export default class MobileLogin {
async getUserAccounts (nucleusUserId) {
const timestamp = new Date().getTime()
- const url = `${this.apiUrl}/ut/game/fifa16/user/accountinfo?sku=FUT16IOS&_=${timestamp}`
+ const url = `${this.apiUrl}/ut/game/fifa16/user/accountinfo?sku=FUT18WEB&_=${timestamp}`
return await this.defaultRequest.getAsync(url, {json: true, headers: {
'Easw-Session-Data-Nucleus-Id': nucleusUserId,
'X-UT-SID': ''
}})
}
- async getNucleusPersonaId (nucleusUserId, powSessionId) {
- const timestamp = new Date().getTime()
- const url = `https://pas.mob.v5.easfc.ea.com:8095/pow/user/self/tiergp/NucleusId/tiertp/${nucleusUserId}?offset=0&count=50&_=${timestamp}`
- const {body} = await this.defaultRequest.getAsync(url, {json: true, headers: {
- 'Easw-Session-Data-Nucleus-Id': nucleusUserId,
- 'X-POW-SID': powSessionId
- }})
-
- return _.findWhere(body.userData.data, {sku: this.options.gameSku}).nucPersId
+ async getNucleusPersonaId (personas) {
+ return personas[0].personaId
+ // return _.findWhere(personas, {sku: this.options.gameSku}).nucPersId
}
async getSid (code, nucleusPersonaId) {
const requestBody = {
- isReadOnly: true,
- sku: 'FUT16IOS',
- clientVersion: 20,
+ isReadOnly: false,
+ sku: 'FUT18WEB',
+ clientVersion: 1,
locale: 'en-US',
method: 'authcode',
priorityLevel: 4,
@@ -312,39 +307,14 @@ export default class MobileLogin {
return response.body.sid
}
- async getPowSid (code) {
- const requestBody = {
- isReadOnly: true,
- sku: 'FUT16IOS',
- clientVersion: 20,
- locale: 'en-US',
- method: 'authcode',
- priorityLevel: 4,
- identification: {
- authCode: code,
- redirectUrl: 'nucleus:rest'
+ async validate (sid) {
+ const uri = `/ut/game/fifa18/phishing/validate?answer=${this.options.secret}`
+ const {body} = await this.api.postAsync(uri, {
+ body: this.options.secret,
+ headers: {
+ 'X-UT-SID': sid
}
- }
- // 1474229595686
- const timestamp = new Date().getTime()
- const url = `https://pas.mob.v5.easfc.ea.com:8095/pow/auth?timestamp=${timestamp}`
- const response = await this.defaultRequest.postAsync(url, {
- body: requestBody,
- json: true
- // headers: {
- // 'X-UT-SID': '',
- // 'X-POW-SID': '',
- // Accept: 'text/plain, */*; q=0.01',
- // Origin: 'file://'
- // }
})
- return response.body.sid
- // return powSid
- }
-
- async validate () {
- const uri = `/ut/game/fifa16/phishing/validate?answer=${this.options.secret}`
- const {body} = await this.api.postAsync(uri, {body: this.options.secret})
return body.token
}
}
@@ -355,37 +325,18 @@ function getTitle (response) {
return title
}
-// example EEA58055-E4E8-42E6-B89D-DFFBBD37AF57
-async function generateMachineKey () {
- let parts = await Promise.all([
- randomHex(8),
- randomHex(4),
- randomHex(4),
- randomHex(4),
- randomHex(12)
- ])
- return `${parts[0]}-${parts[1]}-${parts[2]}-${parts[3]}-${parts[4]}`
-}
-
-async function randomHex (length, uppercase = true) {
- let randomHexStr = await crypto.randomBytesAsync(48)
- randomHexStr = randomHexStr.toString('hex').substring(0, length)
- if (uppercase) randomHexStr = randomHexStr.toUpperCase()
- return randomHexStr
-}
-
function getGameSku (platform) {
switch (platform) {
case 'pc':
- return 'FFA16PCC'
+ return 'FFA18PCC'
case 'ps3':
- return 'FFA16PS3'
+ return 'FFA18PS3'
case 'ps4':
- return 'FFA16PS4'
+ return 'FFA18PS4'
case 'x360':
- return 'FFA16XBX'
+ return 'FFA18XBX'
case 'xone':
- return 'FFA16XBO'
+ return 'FFA18XBO'
}
return null
diff --git a/src/lib/urls.js b/src/lib/urls.js
index b878ab2..04c0123 100644
--- a/src/lib/urls.js
+++ b/src/lib/urls.js
@@ -1,7 +1,7 @@
// @flow
'use strict'
-const urls = (version:number = 17) => {
+const urls = (version:number = 18) => {
return {
referer: `https://www.easports.com/iframe/fut${version}/?baseShowoffUrl=https%3A%2F%2Fwww.easports.com%2Fde%2Ffifa%2Fultimate-team%2Fweb-app%2Fshow-off&guest_app_uri=http%3A%2F%2Fwww.easports.com%2Fde%2Ffifa%2Fultimate-team%2Fweb-app&locale=en_US`,
login: {
@@ -9,7 +9,7 @@ const urls = (version:number = 17) => {
nucleus: `https://www.easports.com/iframe/fut${version}/?locale=en_US&baseShowoffUrl=https%3A%2F%2Fwww.easports.com%2Fde%2Ffifa%2Fultimate-team%2Fweb-app%2Fshow-off&guest_app_uri=http%3A%2F%2Fwww.easports.com%2Fde%2Ffifa%2Fultimate-team%2Fweb-app`,
personas: 'https://www.easports.com/fifa/api/personas',
shards: `https://www.easports.com/iframe/fut${version}/p/ut/shards/v2`,
- accounts: `https://www.easports.com/iframe/fut${version}/p/ut/game/fifa${version}/user/accountinfo?sku=FUT${version}WEB&returningUserGameYear=2015&_=`,
+ accounts: `https://www.easports.com/iframe/fut${version}/p/ut/game/fifa${version}/user/accountinfo?sku=FUT${version}WEB&returningUserGameYear=2017&_=`,
session: `https://www.easports.com/iframe/fut${version}/p/ut/auth`,
question: `https://www.easports.com/iframe/fut${version}/p/ut/game/fifa${version}/phishing/question?redirect=false&_=`,
validate: `https://www.easports.com/iframe/fut${version}/p/ut/game/fifa${version}/phishing/validate?_=`,