alexa-cookie2 4.2.0 → 5.0.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 +7 -0
- package/alexa-cookie.js +103 -74
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -42,6 +42,9 @@ Please use the new method "refreshAlexaCookie" to refresh the cookie data. It ta
|
|
|
42
42
|
|
|
43
43
|
Since 4.0.0 of this library a new key called "macDms" is also returned when cookies are generated or refreshed. This is (right now Oct 2021) needed to use the Push Connection (alexa-remote library). Better strt also persisting this field, might be needed more later on.
|
|
44
44
|
|
|
45
|
+
## Troubleshooting
|
|
46
|
+
If you still use the SMS based 2FA flow then this might now work. Please update the 2fa method in the amazon settings to the current process.
|
|
47
|
+
|
|
45
48
|
## Thanks:
|
|
46
49
|
A big thanks go to soef for the initial version of this library and to many other community users to support in finding out what Amazon changes here and there.
|
|
47
50
|
|
|
@@ -49,6 +52,10 @@ Partly based on [Amazon Alexa Remote Control](http://blog.loetzimmer.de/2017/10/
|
|
|
49
52
|
Thank you for that work.
|
|
50
53
|
|
|
51
54
|
## Changelog:
|
|
55
|
+
### 5.0.0 (2023-09-08)
|
|
56
|
+
* IMPORTANT: Node.js 16 is now required minimum Node.js version!
|
|
57
|
+
* (Apollon77) Enhance registration process by also registering the app capabilities to allow usage of new HTTP/2 push connection
|
|
58
|
+
|
|
52
59
|
### 4.2.0 (2023-08-08)
|
|
53
60
|
* (Hive) Adds the ability to alter the close proxy message
|
|
54
61
|
|
package/alexa-cookie.js
CHANGED
|
@@ -19,8 +19,8 @@ const defaultUserAgentLinux = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.3
|
|
|
19
19
|
const defaultProxyCloseWindowHTML = '<b>Amazon Alexa Cookie successfully retrieved. You can close the browser.</b>';
|
|
20
20
|
const defaultAcceptLanguage = 'de-DE';
|
|
21
21
|
|
|
22
|
-
const apiCallVersion = '2.2.
|
|
23
|
-
const apiCallUserAgent = 'AmazonWebView/Amazon Alexa/2.2.
|
|
22
|
+
const apiCallVersion = '2.2.556530.0';
|
|
23
|
+
const apiCallUserAgent = 'AmazonWebView/Amazon Alexa/2.2.556530.0/iOS/16.6/iPhone';
|
|
24
24
|
const defaultAppName = 'ioBroker Alexa2';
|
|
25
25
|
|
|
26
26
|
const csrfOptions = [
|
|
@@ -182,7 +182,7 @@ function AlexaCookie() {
|
|
|
182
182
|
_options.logger && _options.logger(`Alexa-Cookie: Use as Accept-Language: ${_options.acceptLanguage}`);
|
|
183
183
|
|
|
184
184
|
_options.proxyCloseWindowHTML = _options.proxyCloseWindowHTML || defaultProxyCloseWindowHTML;
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
if (_options.setupProxy && !_options.proxyOwnIp) {
|
|
187
187
|
_options.logger && _options.logger('Alexa-Cookie: Own-IP Setting missing for Proxy. Disabling!');
|
|
188
188
|
_options.setupProxy = false;
|
|
@@ -435,12 +435,7 @@ function AlexaCookie() {
|
|
|
435
435
|
'customer_info'
|
|
436
436
|
],
|
|
437
437
|
'cookies': {
|
|
438
|
-
'website_cookies': [
|
|
439
|
-
/*{
|
|
440
|
-
"Value": cookies["session-id-time"],
|
|
441
|
-
"Name": "session-id-time"
|
|
442
|
-
}*/
|
|
443
|
-
],
|
|
438
|
+
'website_cookies': [],
|
|
444
439
|
'domain': `.${_options.baseAmazonPage}`
|
|
445
440
|
},
|
|
446
441
|
'registration_data': {
|
|
@@ -448,7 +443,7 @@ function AlexaCookie() {
|
|
|
448
443
|
'app_version': apiCallVersion,
|
|
449
444
|
'device_type': 'A2IVLV5VM2W81',
|
|
450
445
|
'device_name': '%FIRST_NAME%\u0027s%DUPE_STRATEGY_1ST%ioBroker Alexa2',
|
|
451
|
-
'os_version': '
|
|
446
|
+
'os_version': '16.6',
|
|
452
447
|
'device_serial': deviceSerial,
|
|
453
448
|
'device_model': 'iPhone',
|
|
454
449
|
'app_name': _options.deviceAppName,
|
|
@@ -524,6 +519,7 @@ function AlexaCookie() {
|
|
|
524
519
|
}
|
|
525
520
|
Cookie = addCookies(Cookie, response.headers);
|
|
526
521
|
loginData.refreshToken = body.response.success.tokens.bearer.refresh_token;
|
|
522
|
+
const accessToken = body.response.success.tokens.bearer.access_token;
|
|
527
523
|
loginData.tokenDate = Date.now();
|
|
528
524
|
loginData.macDms = body.response.success.tokens.mac_dms;
|
|
529
525
|
|
|
@@ -535,78 +531,110 @@ function AlexaCookie() {
|
|
|
535
531
|
Cookie = addCookies(Cookie, {'set-cookie': newCookies});
|
|
536
532
|
}
|
|
537
533
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
534
|
+
registerTokenCapabilities(accessToken, () => {
|
|
535
|
+
/*
|
|
536
|
+
Get Amazon Marketplace Country
|
|
537
|
+
*/
|
|
541
538
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
};
|
|
555
|
-
_options.logger && _options.logger('Alexa-Cookie: Get User data');
|
|
556
|
-
_options.logger && _options.logger(JSON.stringify(options));
|
|
557
|
-
request(options, (error, response, body) => {
|
|
558
|
-
if (!error) {
|
|
559
|
-
try {
|
|
560
|
-
if (typeof body !== 'object') body = JSON.parse(body);
|
|
561
|
-
} catch (err) {
|
|
562
|
-
_options.logger && _options.logger(`Get User data Response: ${JSON.stringify(body)}`);
|
|
563
|
-
callback && callback(err, null);
|
|
564
|
-
return;
|
|
539
|
+
const options = {
|
|
540
|
+
host: `alexa.${_options.baseAmazonPage}`,
|
|
541
|
+
path: `/api/users/me?platform=ios&version=${apiCallVersion}`,
|
|
542
|
+
method: 'GET',
|
|
543
|
+
headers: {
|
|
544
|
+
'User-Agent': apiCallUserAgent,
|
|
545
|
+
'Accept-Language': _options.acceptLanguage,
|
|
546
|
+
'Accept-Charset': 'utf-8',
|
|
547
|
+
'Connection': 'keep-alive',
|
|
548
|
+
'Accept': 'application/json',
|
|
549
|
+
'Cookie': Cookie
|
|
565
550
|
}
|
|
566
|
-
|
|
551
|
+
};
|
|
552
|
+
_options.logger && _options.logger('Alexa-Cookie: Get User data');
|
|
553
|
+
_options.logger && _options.logger(JSON.stringify(options));
|
|
554
|
+
request(options, (error, response, body) => {
|
|
555
|
+
if (!error) {
|
|
556
|
+
try {
|
|
557
|
+
if (typeof body !== 'object') body = JSON.parse(body);
|
|
558
|
+
} catch (err) {
|
|
559
|
+
_options.logger && _options.logger(`Get User data Response: ${JSON.stringify(body)}`);
|
|
560
|
+
callback && callback(err, null);
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
_options.logger && _options.logger(`Get User data Response: ${JSON.stringify(body)}`);
|
|
567
564
|
|
|
568
|
-
|
|
565
|
+
Cookie = addCookies(Cookie, response.headers);
|
|
569
566
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
567
|
+
if (body.marketPlaceDomainName) {
|
|
568
|
+
const pos = body.marketPlaceDomainName.indexOf('.');
|
|
569
|
+
if (pos !== -1) _options.amazonPage = body.marketPlaceDomainName.substr(pos + 1);
|
|
570
|
+
}
|
|
571
|
+
loginData.amazonPage = _options.amazonPage;
|
|
572
|
+
} else if (error && (!_options || !_options.amazonPage)) {
|
|
573
|
+
callback && callback(error, null);
|
|
574
|
+
return;
|
|
575
|
+
} else if (error && (!_options.formerRegistrationData || !_options.formerRegistrationData.amazonPage) && _options.amazonPage) {
|
|
576
|
+
_options.logger && _options.logger(`Continue with externally set amazonPage: ${_options.amazonPage}`);
|
|
577
|
+
} else if (error) {
|
|
578
|
+
_options.logger && _options.logger('Ignore error while getting user data and amazonPage because previously set amazonPage is available');
|
|
573
579
|
}
|
|
574
|
-
loginData.amazonPage = _options.amazonPage;
|
|
575
|
-
} else if (error && (!_options || !_options.amazonPage)) {
|
|
576
|
-
callback && callback(error, null);
|
|
577
|
-
return;
|
|
578
|
-
} else if (error && (!_options.formerRegistrationData || !_options.formerRegistrationData.amazonPage) && _options.amazonPage) {
|
|
579
|
-
_options.logger && _options.logger(`Continue with externally set amazonPage: ${_options.amazonPage}`);
|
|
580
|
-
} else if (error) {
|
|
581
|
-
_options.logger && _options.logger('Ignore error while getting user data and amazonPage because previously set amazonPage is available');
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
loginData.loginCookie = Cookie;
|
|
585
580
|
|
|
586
|
-
|
|
587
|
-
if (err) {
|
|
588
|
-
callback && callback(err, null);
|
|
589
|
-
}
|
|
581
|
+
loginData.loginCookie = Cookie;
|
|
590
582
|
|
|
591
|
-
loginData.localCookie
|
|
592
|
-
getCSRFFromCookies(loginData.localCookie, _options, (err, resData) => {
|
|
583
|
+
getLocalCookies(loginData.amazonPage, loginData.refreshToken, (err, localCookie) => {
|
|
593
584
|
if (err) {
|
|
594
|
-
callback && callback(
|
|
595
|
-
return;
|
|
585
|
+
callback && callback(err, null);
|
|
596
586
|
}
|
|
597
|
-
|
|
598
|
-
loginData.
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
587
|
+
|
|
588
|
+
loginData.localCookie = localCookie;
|
|
589
|
+
getCSRFFromCookies(loginData.localCookie, _options, (err, resData) => {
|
|
590
|
+
if (err) {
|
|
591
|
+
callback && callback(new Error(`Error getting csrf for ${loginData.amazonPage}`), null);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
loginData.localCookie = resData.cookie;
|
|
595
|
+
loginData.csrf = resData.csrf;
|
|
596
|
+
delete loginData.accessToken;
|
|
597
|
+
delete loginData.authorization_code;
|
|
598
|
+
delete loginData.verifier;
|
|
599
|
+
loginData.dataVersion = 2;
|
|
600
|
+
_options.logger && _options.logger(`Final Registration Result: ${JSON.stringify(loginData)}`);
|
|
601
|
+
callback && callback(null, loginData);
|
|
602
|
+
});
|
|
604
603
|
});
|
|
605
604
|
});
|
|
606
605
|
});
|
|
607
606
|
});
|
|
608
607
|
};
|
|
609
608
|
|
|
609
|
+
const registerTokenCapabilities = (accessToken, callback) => {
|
|
610
|
+
/*
|
|
611
|
+
Register Capabilities - mainly needed for HTTP/2 push infos
|
|
612
|
+
*/
|
|
613
|
+
const options = {
|
|
614
|
+
host: `api.amazonalexa.com`, // How Domains needs to be for other regions? au/jp?
|
|
615
|
+
path: `/v1/devices/@self/capabilities`,
|
|
616
|
+
method: 'PUT',
|
|
617
|
+
headers: {
|
|
618
|
+
'User-Agent': apiCallUserAgent,
|
|
619
|
+
'Accept-Language': _options.acceptLanguage,
|
|
620
|
+
'Accept-Charset': 'utf-8',
|
|
621
|
+
'Connection': 'keep-alive',
|
|
622
|
+
'Content-type': 'application/json; charset=UTF-8',
|
|
623
|
+
'authorization': `Bearer ${accessToken}`,
|
|
624
|
+
},
|
|
625
|
+
body: '{"legacyFlags":{"SUPPORTS_COMMS":true,"SUPPORTS_ARBITRATION":true,"SCREEN_WIDTH":1170,"SUPPORTS_SCRUBBING":true,"SPEECH_SYNTH_SUPPORTS_TTS_URLS":false,"SUPPORTS_HOME_AUTOMATION":true,"SUPPORTS_DROPIN_OUTBOUND":true,"FRIENDLY_NAME_TEMPLATE":"VOX","SUPPORTS_SIP_OUTBOUND_CALLING":true,"VOICE_PROFILE_SWITCHING_DISABLED":true,"SUPPORTS_LYRICS_IN_CARD":false,"SUPPORTS_DATAMART_NAMESPACE":"Vox","SUPPORTS_VIDEO_CALLING":true,"SUPPORTS_PFM_CHANGED":true,"SUPPORTS_TARGET_PLATFORM":"TABLET","SUPPORTS_SECURE_LOCKSCREEN":false,"AUDIO_PLAYER_SUPPORTS_TTS_URLS":false,"SUPPORTS_KEYS_IN_HEADER":false,"SUPPORTS_MIXING_BEHAVIOR_FOR_AUDIO_PLAYER":false,"AXON_SUPPORT":true,"SUPPORTS_TTS_SPEECHMARKS":true},"envelopeVersion":"20160207","capabilities":[{"version":"0.1","interface":"CardRenderer","type":"AlexaInterface"},{"interface":"Navigation","type":"AlexaInterface","version":"1.1"},{"type":"AlexaInterface","version":"2.0","interface":"Alexa.Comms.PhoneCallController"},{"type":"AlexaInterface","version":"1.1","interface":"ExternalMediaPlayer"},{"type":"AlexaInterface","interface":"Alerts","configurations":{"maximumAlerts":{"timers":2,"overall":99,"alarms":2}},"version":"1.3"},{"version":"1.0","interface":"Alexa.Display.Window","type":"AlexaInterface","configurations":{"templates":[{"type":"STANDARD","id":"app_window_template","configuration":{"sizes":[{"id":"fullscreen","type":"DISCRETE","value":{"value":{"height":1440,"width":3200},"unit":"PIXEL"}}],"interactionModes":["mobile_mode","auto_mode"]}}]}},{"type":"AlexaInterface","interface":"AccessoryKit","version":"0.1"},{"type":"AlexaInterface","interface":"Alexa.AudioSignal.ActiveNoiseControl","version":"1.0","configurations":{"ambientSoundProcessingModes":[{"name":"ACTIVE_NOISE_CONTROL"},{"name":"PASSTHROUGH"}]}},{"interface":"PlaybackController","type":"AlexaInterface","version":"1.0"},{"version":"1.0","interface":"Speaker","type":"AlexaInterface"},{"version":"1.0","interface":"SpeechSynthesizer","type":"AlexaInterface"},{"version":"1.0","interface":"AudioActivityTracker","type":"AlexaInterface"},{"type":"AlexaInterface","interface":"Alexa.Camera.LiveViewController","version":"1.0"},{"type":"AlexaInterface","version":"1.0","interface":"Alexa.Input.Text"},{"type":"AlexaInterface","interface":"Alexa.PlaybackStateReporter","version":"1.0"},{"version":"1.1","interface":"Geolocation","type":"AlexaInterface"},{"interface":"Alexa.Health.Fitness","version":"1.0","type":"AlexaInterface"},{"interface":"Settings","type":"AlexaInterface","version":"1.0"},{"configurations":{"interactionModes":[{"dialog":"SUPPORTED","interactionDistance":{"value":18,"unit":"INCHES"},"video":"SUPPORTED","keyboard":"SUPPORTED","id":"mobile_mode","uiMode":"MOBILE","touch":"SUPPORTED"},{"video":"UNSUPPORTED","dialog":"SUPPORTED","interactionDistance":{"value":36,"unit":"INCHES"},"uiMode":"AUTO","touch":"SUPPORTED","id":"auto_mode","keyboard":"UNSUPPORTED"}]},"type":"AlexaInterface","interface":"Alexa.InteractionMode","version":"1.0"},{"type":"AlexaInterface","configurations":{"catalogs":[{"type":"IOS_APP_STORE","identifierTypes":["URI_HTTP_SCHEME","URI_CUSTOM_SCHEME"]}]},"version":"0.2","interface":"Alexa.Launcher"},{"interface":"System","version":"1.0","type":"AlexaInterface"},{"interface":"Alexa.IOComponents","type":"AlexaInterface","version":"1.4"},{"type":"AlexaInterface","interface":"Alexa.FavoritesController","version":"1.0"},{"version":"1.0","type":"AlexaInterface","interface":"Alexa.Mobile.Push"},{"type":"AlexaInterface","interface":"InteractionModel","version":"1.1"},{"interface":"Alexa.PlaylistController","type":"AlexaInterface","version":"1.0"},{"interface":"SpeechRecognizer","type":"AlexaInterface","version":"2.1"},{"interface":"AudioPlayer","type":"AlexaInterface","version":"1.3"},{"type":"AlexaInterface","version":"3.1","interface":"Alexa.RTCSessionController"},{"interface":"VisualActivityTracker","version":"1.1","type":"AlexaInterface"},{"interface":"Alexa.PlaybackController","version":"1.0","type":"AlexaInterface"},{"type":"AlexaInterface","interface":"Alexa.SeekController","version":"1.0"},{"interface":"Alexa.Comms.MessagingController","type":"AlexaInterface","version":"1.0"}]}'
|
|
626
|
+
};
|
|
627
|
+
_options.logger && _options.logger('Alexa-Cookie: Register capabilities');
|
|
628
|
+
_options.logger && _options.logger(JSON.stringify(options));
|
|
629
|
+
request(options, (error, response, body) => {
|
|
630
|
+
if (error || (response.statusCode !== 204 && response.statusCode !== 200)) {
|
|
631
|
+
_options.logger && _options.logger('Alexa-Cookie: Could not set capabilities, Push connection might not work!');
|
|
632
|
+
_options.logger && _options.logger(`Alexa-Cookie: ${JSON.stringify(error)}: ${JSON.stringify(body)}`);
|
|
633
|
+
}
|
|
634
|
+
callback && callback();
|
|
635
|
+
});
|
|
636
|
+
};
|
|
637
|
+
|
|
610
638
|
const getLocalCookies = (amazonPage, refreshToken, callback) => {
|
|
611
639
|
Cookie = ''; // Reset because we are switching domains
|
|
612
640
|
/*
|
|
@@ -621,10 +649,9 @@ function AlexaCookie() {
|
|
|
621
649
|
'requested_token_type': 'auth_cookies',
|
|
622
650
|
'source_token_type': 'refresh_token',
|
|
623
651
|
'di.hw.version': 'iPhone',
|
|
624
|
-
'di.sdk.version': '6.12.
|
|
625
|
-
'cookies': Buffer.from(`{„cookies“:{".${amazonPage}":[]}}`).toString('base64'),
|
|
652
|
+
'di.sdk.version': '6.12.4',
|
|
626
653
|
'app_name': _options.deviceAppName || defaultAppName,
|
|
627
|
-
'di.os.version': '
|
|
654
|
+
'di.os.version': '16.6'
|
|
628
655
|
};
|
|
629
656
|
const options = {
|
|
630
657
|
host: `www.${amazonPage}`,
|
|
@@ -636,7 +663,9 @@ function AlexaCookie() {
|
|
|
636
663
|
'Accept-Charset': 'utf-8',
|
|
637
664
|
'Connection': 'keep-alive',
|
|
638
665
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
639
|
-
'Accept': '*/*'
|
|
666
|
+
'Accept': '*/*',
|
|
667
|
+
'Cookie': Cookie,
|
|
668
|
+
'x-amzn-identity-auth-domain': `api.${amazonPage}`
|
|
640
669
|
},
|
|
641
670
|
body: querystring.stringify(exchangeParams, null, null, {
|
|
642
671
|
encodeURIComponent: encodeURIComponent
|
|
@@ -709,7 +738,7 @@ function AlexaCookie() {
|
|
|
709
738
|
const refreshData = {
|
|
710
739
|
'app_name': _options.deviceAppName || defaultAppName,
|
|
711
740
|
'app_version': apiCallVersion,
|
|
712
|
-
'di.sdk.version': '6.12.
|
|
741
|
+
'di.sdk.version': '6.12.4',
|
|
713
742
|
'source_token': _options.formerRegistrationData.refreshToken,
|
|
714
743
|
'package_name': 'com.amazon.echo',
|
|
715
744
|
'di.hw.version': 'iPhone',
|
|
@@ -717,8 +746,8 @@ function AlexaCookie() {
|
|
|
717
746
|
'requested_token_type': 'access_token',
|
|
718
747
|
'source_token_type': 'refresh_token',
|
|
719
748
|
'di.os.name': 'iOS',
|
|
720
|
-
'di.os.version': '
|
|
721
|
-
'current_version': '6.12.
|
|
749
|
+
'di.os.version': '16.6',
|
|
750
|
+
'current_version': '6.12.4'
|
|
722
751
|
};
|
|
723
752
|
|
|
724
753
|
const options = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alexa-cookie2",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "Generate Cookie and CSRF for Alexa Remote",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Apollon77",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@alcalzone/release-script": "^3.6.0",
|
|
33
33
|
"@alcalzone/release-script-plugin-license": "^3.5.9",
|
|
34
|
-
"eslint": "^8.
|
|
34
|
+
"eslint": "^8.48.0"
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"release": "release-script"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
|
-
"node": ">=
|
|
47
|
+
"node": ">=16.0.0"
|
|
48
48
|
},
|
|
49
49
|
"main": "alexa-cookie.js",
|
|
50
50
|
"readmeFilename": "readme.md"
|