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 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.485407.0';
23
- const apiCallUserAgent = 'AmazonWebView/Amazon Alexa/2.2.485407.0/iOS/15.5/iPhone';
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': '15.5',
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
- Get Amazon Marketplace Country
540
- */
534
+ registerTokenCapabilities(accessToken, () => {
535
+ /*
536
+ Get Amazon Marketplace Country
537
+ */
541
538
 
542
- const options = {
543
- host: `alexa.${_options.baseAmazonPage}`,
544
- path: `/api/users/me?platform=ios&version=${apiCallVersion}`,
545
- method: 'GET',
546
- headers: {
547
- 'User-Agent': apiCallUserAgent,
548
- 'Accept-Language': _options.acceptLanguage,
549
- 'Accept-Charset': 'utf-8',
550
- 'Connection': 'keep-alive',
551
- 'Accept': 'application/json',
552
- 'Cookie': Cookie
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
- _options.logger && _options.logger(`Get User data Response: ${JSON.stringify(body)}`);
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
- Cookie = addCookies(Cookie, response.headers);
565
+ Cookie = addCookies(Cookie, response.headers);
569
566
 
570
- if (body.marketPlaceDomainName) {
571
- const pos = body.marketPlaceDomainName.indexOf('.');
572
- if (pos !== -1) _options.amazonPage = body.marketPlaceDomainName.substr(pos + 1);
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
- getLocalCookies(loginData.amazonPage, loginData.refreshToken, (err, localCookie) => {
587
- if (err) {
588
- callback && callback(err, null);
589
- }
581
+ loginData.loginCookie = Cookie;
590
582
 
591
- loginData.localCookie = localCookie;
592
- getCSRFFromCookies(loginData.localCookie, _options, (err, resData) => {
583
+ getLocalCookies(loginData.amazonPage, loginData.refreshToken, (err, localCookie) => {
593
584
  if (err) {
594
- callback && callback(new Error(`Error getting csrf for ${loginData.amazonPage}`), null);
595
- return;
585
+ callback && callback(err, null);
596
586
  }
597
- loginData.localCookie = resData.cookie;
598
- loginData.csrf = resData.csrf;
599
- delete loginData.accessToken;
600
- delete loginData.authorization_code;
601
- delete loginData.verifier;
602
- _options.logger && _options.logger(`Final Registration Result: ${JSON.stringify(loginData)}`);
603
- callback && callback(null, loginData);
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.3',
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': '15.5'
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.3',
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': '15.5',
721
- 'current_version': '6.12.3'
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": "4.2.0",
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.46.0"
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": ">=12.0.0"
47
+ "node": ">=16.0.0"
48
48
  },
49
49
  "main": "alexa-cookie.js",
50
50
  "readmeFilename": "readme.md"