@@ -8,25 +8,30 @@ import {
88} from './base'
99import { Config } from '../../config'
1010
11- const DEFAULT_API_DOMAIN = 'https:// mybluelink.ca/tods/api/ '
11+ const DEFAULT_API_DOMAIN = 'mybluelink.ca'
1212const API_DOMAINS : Record < string , string > = {
13- hyundai : 'https:// mybluelink.ca/tods/api/ ' ,
14- kia : 'https:// kiaconnect.ca/tods/api/ ' ,
13+ hyundai : 'mybluelink.ca' ,
14+ kia : 'kiaconnect.ca' ,
1515}
1616
1717const MAX_COMPLETION_POLLS = 20
1818
1919export class BluelinkCanada extends Bluelink {
2020 constructor ( config : Config , statusCheckInterval ?: number ) {
2121 super ( config )
22- this . apiDomain = config . manufacturer
22+ this . apiHost = config . manufacturer
2323 ? this . getApiDomain ( config . manufacturer , API_DOMAINS , DEFAULT_API_DOMAIN )
2424 : DEFAULT_API_DOMAIN
25+ this . apiDomain = `https://${ this . apiHost } /tods/api/`
2526 this . statusCheckInterval = statusCheckInterval || DEFAULT_STATUS_CHECK_INTERVAL
2627 this . additionalHeaders = {
27- from : 'CWP' ,
28+ from : 'SPA' ,
29+ client_id : 'HATAHSPACA0232141ED9722C67715A0B' ,
30+ client_secret : 'CLISCR01AHSPA' ,
2831 language : '0' ,
32+ brand : this . apiHost === 'mybluelink.ca' ? 'H' : 'kia' ,
2933 offset : `-${ new Date ( ) . getTimezoneOffset ( ) / 60 } ` ,
34+ 'User-Agent' : 'MyHyundai/2.0.25 (iPhone; iOS 18.3; Scale/3.00)' ,
3035 }
3136 this . authHeader = 'Accesstoken'
3237 this . tempLookup = {
@@ -64,26 +69,61 @@ export class BluelinkCanada extends Bluelink {
6469 return obj
6570 }
6671
67- private requestResponseValid ( payload : any ) : boolean {
72+ private requestResponseValid (
73+ resp : Record < string , any > ,
74+ payload : Record < string , any > ,
75+ ) : { valid : boolean ; retry : boolean } {
6876 if ( Object . hasOwn ( payload , 'responseHeader' ) && payload . responseHeader . responseCode == 0 ) {
69- return true
77+ return { valid : true , retry : false }
7078 }
71- return false
79+ if ( Object . hasOwn ( payload , 'responseHeader' ) && payload . responseHeader . responseCode == 1 ) {
80+ // check failure
81+ if (
82+ Object . hasOwn ( payload , 'error' ) &&
83+ Object . hasOwn ( payload . error , 'errorDesc' ) &&
84+ ( payload . error . errorDesc . toLocaleString ( ) . includes ( 'expired' ) ||
85+ payload . error . errorDesc . toLocaleString ( ) . includes ( 'deleted' ) ||
86+ payload . error . errorDesc . toLocaleString ( ) . includes ( 'ip validation' ) )
87+ ) {
88+ return { valid : false , retry : true }
89+ }
90+ }
91+ return { valid : false , retry : false }
92+ }
93+
94+ protected async getSessionCookie ( ) : Promise < string > {
95+ const req = new Request ( `https://${ this . apiHost } /login` )
96+ req . headers = this . additionalHeaders
97+ req . method = 'GET'
98+ await req . load ( )
99+ for ( const cookie of req . response . cookies ) {
100+ if ( cookie . name === 'dtCookie' ) {
101+ return `dtCookie=${ cookie . value } `
102+ }
103+ }
104+ return ''
72105 }
73106
74107 protected async login ( ) : Promise < BluelinkTokens | undefined > {
108+ // get cookie
109+ const cookieValue = await this . getSessionCookie ( )
75110 const resp = await this . request ( {
76111 url : this . apiDomain + 'v2/login' ,
77112 data : JSON . stringify ( {
78113 loginId : this . config . auth . username ,
79114 password : this . config . auth . password ,
80115 } ) ,
116+ headers : {
117+ Cookie : cookieValue ,
118+ } ,
81119 noAuth : true ,
120+ validResponseFunction : this . requestResponseValid ,
82121 } )
83- if ( this . requestResponseValid ( resp . json ) ) {
122+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
84123 return {
85124 accessToken : resp . json . result . token . accessToken ,
86125 expiry : Math . floor ( Date . now ( ) / 1000 ) + resp . json . result . token . expireIn , // we only get a expireIn not a actual date
126+ authCookie : cookieValue ,
87127 }
88128 }
89129
@@ -98,8 +138,9 @@ export class BluelinkCanada extends Bluelink {
98138 data : JSON . stringify ( {
99139 vehicleId : id ,
100140 } ) ,
141+ validResponseFunction : this . requestResponseValid ,
101142 } )
102- if ( ! this . requestResponseValid ( resp . json ) ) {
143+ if ( ! this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
103144 const error = `Failed to set car ${ id } : ${ JSON . stringify ( resp . json ) } request ${ JSON . stringify ( this . debugLastRequest ) } `
104145 if ( this . config . debugLogging ) await this . logger . log ( error )
105146 throw Error ( error )
@@ -110,8 +151,9 @@ export class BluelinkCanada extends Bluelink {
110151 const resp = await this . request ( {
111152 url : this . apiDomain + 'vhcllst' ,
112153 method : 'POST' ,
154+ validResponseFunction : this . requestResponseValid ,
113155 } )
114- if ( this . requestResponseValid ( resp . json ) && resp . json . result . vehicles . length > 0 ) {
156+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid && resp . json . result . vehicles . length > 0 ) {
115157 let vehicle = resp . json . result . vehicles [ 0 ]
116158 if ( this . vin ) {
117159 for ( const v of resp . json . result . vehicles ) {
@@ -202,9 +244,10 @@ export class BluelinkCanada extends Bluelink {
202244 headers : {
203245 Vehicleid : id ,
204246 } ,
247+ validResponseFunction : this . requestResponseValid ,
205248 } )
206249
207- if ( this . requestResponseValid ( resp . json ) ) {
250+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
208251 return forceUpdate
209252 ? this . returnCarStatus ( resp . json . result . status , forceUpdate , resp . json . result . status . odometer )
210253 : this . returnCarStatus ( resp . json . result . status , forceUpdate , resp . json . result . vehicle . odometer )
@@ -223,8 +266,10 @@ export class BluelinkCanada extends Bluelink {
223266 data : JSON . stringify ( {
224267 pin : this . config . auth . pin ,
225268 } ) ,
269+ validResponseFunction : this . requestResponseValid ,
270+ headers : { } ,
226271 } )
227- if ( this . requestResponseValid ( resp . json ) ) {
272+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
228273 return resp . json . result . pAuth
229274 }
230275 const error = `Failed to get auth code: ${ JSON . stringify ( resp . json ) } request ${ JSON . stringify ( this . debugLastRequest ) } `
@@ -248,9 +293,10 @@ export class BluelinkCanada extends Bluelink {
248293 Pauth : authCode ,
249294 TransactionId : transactionId ,
250295 } ,
296+ validResponseFunction : this . requestResponseValid ,
251297 } )
252298
253- if ( ! this . requestResponseValid ( resp . json ) ) {
299+ if ( ! this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
254300 const error = `Failed to poll for command completion: ${ JSON . stringify ( resp . json ) } request ${ JSON . stringify ( this . debugLastRequest ) } `
255301 if ( this . config . debugLogging ) await this . logger . log ( error )
256302 throw Error ( error )
@@ -297,8 +343,9 @@ export class BluelinkCanada extends Bluelink {
297343 Vehicleid : id ,
298344 Pauth : authCode ,
299345 } ,
346+ validResponseFunction : this . requestResponseValid ,
300347 } )
301- if ( this . requestResponseValid ( resp . json ) ) {
348+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
302349 const transactionId = resp . resp . headers . transactionId
303350 return await this . pollForCommandCompletion ( id , authCode , transactionId )
304351 }
@@ -331,8 +378,9 @@ export class BluelinkCanada extends Bluelink {
331378 Vehicleid : id ,
332379 Pauth : authCode ,
333380 } ,
381+ validResponseFunction : this . requestResponseValid ,
334382 } )
335- if ( this . requestResponseValid ( resp . json ) ) {
383+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
336384 const transactionId = resp . resp . headers . transactionId
337385 return await this . pollForCommandCompletion ( id , authCode , transactionId )
338386 }
@@ -374,8 +422,9 @@ export class BluelinkCanada extends Bluelink {
374422 Vehicleid : id ,
375423 Pauth : authCode ,
376424 } ,
425+ validResponseFunction : this . requestResponseValid ,
377426 } )
378- if ( this . requestResponseValid ( resp . json ) ) {
427+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
379428 const transactionId = resp . resp . headers . transactionId
380429 return await this . pollForCommandCompletion ( id , authCode , transactionId )
381430 }
@@ -397,8 +446,9 @@ export class BluelinkCanada extends Bluelink {
397446 Vehicleid : id ,
398447 Pauth : authCode ,
399448 } ,
449+ validResponseFunction : this . requestResponseValid ,
400450 } )
401- if ( this . requestResponseValid ( resp . json ) ) {
451+ if ( this . requestResponseValid ( resp . resp , resp . json ) . valid ) {
402452 const transactionId = resp . resp . headers . transactionId
403453 return await this . pollForCommandCompletion ( id , authCode , transactionId )
404454 }
0 commit comments