alexa-cookie2 3.4.3 → 4.0.2

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/.eslintrc.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "root": true,
3
+ "env": {
4
+ "es6": true,
5
+ "node": true,
6
+ "mocha": true
7
+ },
8
+ "extends": [
9
+ "eslint:recommended"
10
+ ],
11
+ "plugins": [],
12
+ "rules": {
13
+ "indent": [
14
+ "error",
15
+ 4,
16
+ {
17
+ "SwitchCase": 1
18
+ }
19
+ ],
20
+ "no-console": "off",
21
+ "no-var": "error",
22
+ "no-trailing-spaces": "error",
23
+ "prefer-const": "error",
24
+ "quotes": [
25
+ "error",
26
+ "single",
27
+ {
28
+ "avoidEscape": true,
29
+ "allowTemplateLiterals": true
30
+ }
31
+ ],
32
+ "semi": [
33
+ "error",
34
+ "always"
35
+ ]
36
+ },
37
+ "parserOptions": {
38
+ "ecmaVersion": 2018
39
+ }
40
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "plugins": ["license"]
3
+ }
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2018-2020 Apollon77 <ingo@fischer-ka.de>
3
+ Copyright (c) 2018-2022 Apollon77 <ingo@fischer-ka.de>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # alexa-cookie
2
2
 
3
+ [![NPM version](http://img.shields.io/npm/v/alexa-cookie2.svg)](https://www.npmjs.com/package/alexa-cookie2)
4
+ [![Downloads](https://img.shields.io/npm/dm/alexa-cookie2.svg)](https://www.npmjs.com/package/alexa-cookie2)
5
+ ![Test and Release](https://github.com/Apollon77/alexa-cookie/workflows/Test%20and%20Release/badge.svg)
6
+
3
7
  Library to generate/retrieve a cookie including a csrf for alexa remote
4
8
 
5
- <!--
6
- [![NPM version](http://img.shields.io/npm/v/alexa-remote.svg)](https://www.npmjs.com/package/alexa-remote)
7
- [![Tests](http://img.shields.io/travis/soef/alexa-remote/master.svg)](https://travis-ci.org/soef/alexa-remote)
8
- -->
9
- [![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/soef/alexa-remote/blob/master/LICENSE)
9
+ ## Disclaimer
10
+ **All product and company names or logos are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them or any associated subsidiaries! This personal project is maintained in spare time and has no business goal.**
11
+ **ALEXA is a trademark of AMAZON TECHNOLOGIES, INC.**
10
12
 
11
13
  ## Description
12
14
  This library can be used to get the cookies needed to access Amazon Alexa services from outside. It authenticates with Amazon and gathers all needed details. These details are returned in the callback.
@@ -36,15 +38,28 @@ Important for the further interaction with alexa are the keys "localCookie" (sam
36
38
 
37
39
  If you not do this a new device is created each time the proxy is used which can end up in having many unused devices (such a device is like a mobile phone where you use the Alexa App with).
38
40
 
39
- Please use the new method "refreshAlexaCookie" to refresh the cookie data. It takes the same options object as the other method and requires the key "formerRegistrationData". It returns an updated object will all data as above. Please also store this and provide for susequent calls!
41
+ Please use the new method "refreshAlexaCookie" to refresh the cookie data. It takes the same options object as the other method and requires the key "formerRegistrationData". It returns an updated object will all data as above. Please also store this and provide for subsequent calls!
42
+
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.
40
44
 
41
45
  ## Thanks:
42
- A big thanks go to soef for the initial version of this library.
46
+ 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.
43
47
 
44
48
  Partly based on [Amazon Alexa Remote Control](http://blog.loetzimmer.de/2017/10/amazon-alexa-hort-auf-die-shell-echo.html) (PLAIN shell) and [alexa-remote-control](https://github.com/thorsten-gehrig/alexa-remote-control) and the the Proxy idea from [OpenHab-Addon](https://github.com/openhab/openhab2-addons/blob/f54c9b85016758ff6d271b62d255bbe41a027928/addons/binding/org.openhab.binding.amazonechocontrol). Also the new way to refresh cookie and all needed changes were developed in close cooperation with @mgeramb
45
49
  Thank you for that work.
46
50
 
47
51
  ## Changelog:
52
+ ### 4.0.2 (2022-06-30)
53
+ * (Apollon77) Prevent potential crash cases
54
+
55
+ ### 4.0.1 (2021-10-11)
56
+ * (Apollon77) Adjust call headers
57
+
58
+ ### 4.0.0 (2021-10-11)
59
+ * IMPORTANT: Node.js 10 support is dropped, supports LTS versions of Node.js starting with 12.x
60
+ * (Apollon77) Add support to get macDms with relevant data from the device registration process to use in push connection.
61
+ * (adn77) Update Login Flow to use match to most current Alexa App flow using code auth
62
+ * (Apollon77) Update deps, drop Node.js 10 support
48
63
 
49
64
  ### 3.4.3 (2021-04-18)
50
65
  * (Apollon77) handle potential crash case (Sentry IOBROKER-ALEXA2-86)
package/alexa-cookie.js CHANGED
@@ -1,10 +1,3 @@
1
- /* jshint -W097 */
2
- /* jshint -W030 */
3
- /* jshint strict: false */
4
- /* jslint node: true */
5
- /* jslint esversion: 6 */
6
- "use strict";
7
-
8
1
  /**
9
2
  * partly based on Amazon Alexa Remote Control (PLAIN shell)
10
3
  * http://blog.loetzimmer.de/2017/10/amazon-alexa-hort-auf-die-shell-echo.html AND on
@@ -57,7 +50,7 @@ function AlexaCookie() {
57
50
  }
58
51
  }
59
52
  Cookie = '';
60
- for (let name in cookies) {
53
+ for (const name in cookies) {
61
54
  if (!cookies.hasOwnProperty(name)) continue;
62
55
  Cookie += name + '=' + cookies[name] + '; ';
63
56
  }
@@ -83,14 +76,14 @@ function AlexaCookie() {
83
76
  removeContentLength = true;
84
77
  }
85
78
 
86
- let req = https.request(options, (res) => {
87
- let body = "";
79
+ const req = https.request(options, (res) => {
80
+ let body = '';
88
81
  info.requests.push({options: options, response: res});
89
82
 
90
83
  if (options.followRedirects !== false && res.statusCode >= 300 && res.statusCode < 400) {
91
84
  _options.logger && _options.logger('Alexa-Cookie: Response (' + res.statusCode + ')' + (res.headers.location ? ' - Redirect to ' + res.headers.location : ''));
92
85
  //options.url = res.headers.location;
93
- let u = url.parse(res.headers.location);
86
+ const u = url.parse(res.headers.location);
94
87
  if (u.host) options.host = u.host;
95
88
  options.path = u.path;
96
89
  options.method = 'GET';
@@ -127,11 +120,11 @@ function AlexaCookie() {
127
120
  const getFields = body => {
128
121
  body = body.replace(/[\n\r]/g, ' ');
129
122
  let re = /^.*?("hidden"\s*name=".*$)/;
130
- let ar = re.exec(body);
123
+ const ar = re.exec(body);
131
124
  if (!ar || ar.length < 2) return {};
132
125
  let h;
133
126
  re = /.*?name="([^"]+)"[\s^\s]*value="([^"]+).*?"/g;
134
- let data = {};
127
+ const data = {};
135
128
  while ((h = re.exec(ar[1])) !== null) {
136
129
  if (h[1] !== 'rememberMe') {
137
130
  data[h[1]] = h[2];
@@ -164,7 +157,7 @@ function AlexaCookie() {
164
157
  }
165
158
 
166
159
  if (!_options.userAgent) {
167
- let platform = os.platform();
160
+ const platform = os.platform();
168
161
  if (platform === 'win32') {
169
162
  _options.userAgent = defaultUserAgent;
170
163
  }
@@ -205,7 +198,7 @@ function AlexaCookie() {
205
198
 
206
199
  function csrfTry() {
207
200
  const path = csrfUrls.shift();
208
- let options = {
201
+ const options = {
209
202
  'host': 'alexa.' + _options.amazonPage,
210
203
  'path': path,
211
204
  'method': 'GET',
@@ -223,8 +216,8 @@ function AlexaCookie() {
223
216
  _options.logger && _options.logger('Alexa-Cookie: Step 4: get CSRF via ' + path);
224
217
  request(options, (error, response) => {
225
218
  cookie = addCookies(cookie, response ? response.headers : null);
226
- let ar = /csrf=([^;]+)/.exec(cookie);
227
- let csrf = ar ? ar[1] : undefined;
219
+ const ar = /csrf=([^;]+)/.exec(cookie);
220
+ const csrf = ar ? ar[1] : undefined;
228
221
  _options.logger && _options.logger('Alexa-Cookie: Result: csrf=' + csrf + ', Cookie=' + cookie);
229
222
  if (!csrf && csrfUrls.length) {
230
223
  csrfTry();
@@ -268,7 +261,7 @@ function AlexaCookie() {
268
261
 
269
262
  if (!_options.proxyOnly) {
270
263
  // get first cookie and write redirection target into referer
271
- let options = {
264
+ const options = {
272
265
  host: 'alexa.' + _options.amazonPage,
273
266
  path: '',
274
267
  method: 'GET',
@@ -288,10 +281,10 @@ function AlexaCookie() {
288
281
  return;
289
282
  }
290
283
 
291
- let lastRequestOptions = info.requests[info.requests.length - 1].options;
284
+ const lastRequestOptions = info.requests[info.requests.length - 1].options;
292
285
  // login empty to generate session
293
286
  Cookie = addCookies(Cookie, response.headers);
294
- let options = {
287
+ const options = {
295
288
  host: 'www.' + _options.amazonPage,
296
289
  path: '/ap/signin',
297
290
  method: 'POST',
@@ -322,7 +315,7 @@ function AlexaCookie() {
322
315
  options.path = '/ap/signin';
323
316
  options.method = 'POST';
324
317
  options.headers.Cookie = Cookie = addCookies(Cookie, response.headers);
325
- let ar = options.headers.Cookie.match(/session-id=([^;]+)/);
318
+ const ar = options.headers.Cookie.match(/session-id=([^;]+)/);
326
319
  options.headers.Referer = `https://www.${_options.amazonPage}/ap/signin/${ar[1]}`;
327
320
  options.body = getFields(body);
328
321
  options.body.email = email || '';
@@ -336,7 +329,7 @@ function AlexaCookie() {
336
329
  return;
337
330
  }
338
331
 
339
- let lastRequestOptions = info.requests[info.requests.length - 1].options;
332
+ const lastRequestOptions = info.requests[info.requests.length - 1].options;
340
333
 
341
334
  // check whether the login has been successful or exit otherwise
342
335
  if (!lastRequestOptions.host.startsWith('alexa') || !lastRequestOptions.path.endsWith('.html')) {
@@ -389,7 +382,7 @@ function AlexaCookie() {
389
382
  }
390
383
 
391
384
  function prepareResult(err, data) {
392
- if (err || !data.accessToken) {
385
+ if (err || !data.authorization_code) {
393
386
  callback && callback(err, data.loginCookie);
394
387
  return;
395
388
  }
@@ -422,62 +415,75 @@ function AlexaCookie() {
422
415
  */
423
416
 
424
417
  const registerData = {
425
- "requested_extensions": [
426
- "device_info",
427
- "customer_info"
418
+ 'requested_extensions': [
419
+ 'device_info',
420
+ 'customer_info'
428
421
  ],
429
- "cookies": {
430
- "website_cookies": [
422
+ 'cookies': {
423
+ 'website_cookies': [
431
424
  /*{
432
425
  "Value": cookies["session-id-time"],
433
426
  "Name": "session-id-time"
434
427
  }*/
435
428
  ],
436
- "domain": "." + _options.baseAmazonPage
429
+ 'domain': '.' + _options.baseAmazonPage
437
430
  },
438
- "registration_data": {
439
- "domain": "Device",
440
- "app_version": "2.2.223830.0",
441
- "device_type": "A2IVLV5VM2W81",
442
- "device_name": "%FIRST_NAME%\u0027s%DUPE_STRATEGY_1ST%ioBroker Alexa2",
443
- "os_version": "11.4.1",
444
- "device_serial": deviceSerial,
445
- "device_model": "iPhone",
446
- "app_name": "ioBroker Alexa2",
447
- "software_version": "1"
431
+ 'registration_data': {
432
+ 'domain': 'Device',
433
+ 'app_version': '2.2.443692.0',
434
+ 'device_type': 'A2IVLV5VM2W81',
435
+ 'device_name': '%FIRST_NAME%\u0027s%DUPE_STRATEGY_1ST%ioBroker Alexa2',
436
+ 'os_version': '14.8',
437
+ 'device_serial': deviceSerial,
438
+ 'device_model': 'iPhone',
439
+ 'app_name': 'ioBroker Alexa2',
440
+ 'software_version': '1'
448
441
  },
449
- "auth_data": {
450
- "access_token": loginData.accessToken
442
+ 'auth_data': {
443
+ // Filled below
451
444
  },
452
- "user_context_map": {
453
- "frc": cookies.frc
445
+ 'user_context_map': {
446
+ 'frc': cookies.frc
454
447
  },
455
- "requested_token_type": [
456
- "bearer",
457
- "mac_dms",
458
- "website_cookies"
448
+ 'requested_token_type': [
449
+ 'bearer',
450
+ 'mac_dms',
451
+ 'website_cookies'
459
452
  ]
460
453
  };
461
- for (let key in cookies) {
454
+ if (loginData.accessToken) {
455
+ registerData.auth_data = {
456
+ 'access_token': loginData.accessToken
457
+ };
458
+ } else if (loginData.authorization_code && loginData.verifier) {
459
+ registerData.auth_data = {
460
+ 'client_id' : loginData.deviceId,
461
+ 'authorization_code' : loginData.authorization_code,
462
+ 'code_verifier' : loginData.verifier,
463
+ 'code_algorithm' : 'SHA-256',
464
+ 'client_domain' : 'DeviceLegacy'
465
+ };
466
+ }
467
+ for (const key in cookies) {
462
468
  if (!cookies.hasOwnProperty(key)) continue;
463
469
  registerData.cookies.website_cookies.push({
464
- "Value": cookies[key],
465
- "Name": key
470
+ 'Value': cookies[key],
471
+ 'Name': key
466
472
  });
467
473
  }
468
474
 
469
- let options = {
475
+ const options = {
470
476
  host: 'api.' + _options.baseAmazonPage,
471
477
  path: '/auth/register',
472
478
  method: 'POST',
473
479
  headers: {
474
- 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.223830.0/iOS/11.4.1/iPhone',
480
+ 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.443692.0/iOS/14.8/iPhone',
475
481
  'Accept-Language': _options.acceptLanguage,
476
482
  'Accept-Charset': 'utf-8',
477
483
  'Connection': 'keep-alive',
478
484
  'Content-Type': 'application/json',
479
485
  'Cookie': loginData.loginCookie,
480
- 'Accept': '*/*',
486
+ 'Accept': 'application/json',
481
487
  'x-amzn-identity-auth-domain': 'api.' + _options.baseAmazonPage
482
488
  },
483
489
  body: JSON.stringify(registerData)
@@ -505,18 +511,18 @@ function AlexaCookie() {
505
511
  Cookie = addCookies(Cookie, response.headers);
506
512
  loginData.refreshToken = body.response.success.tokens.bearer.refresh_token;
507
513
  loginData.tokenDate = Date.now();
508
-
514
+ loginData.macDms = body.response.success.tokens.mac_dms;
509
515
 
510
516
  /*
511
517
  Get Amazon Marketplace Country
512
518
  */
513
519
 
514
- let options = {
520
+ const options = {
515
521
  host: 'alexa.' + _options.baseAmazonPage,
516
- path: '/api/users/me?platform=ios&version=2.2.223830.0',
522
+ path: '/api/users/me?platform=ios&version=2.2.443692.0',
517
523
  method: 'GET',
518
524
  headers: {
519
- 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.223830.0/iOS/11.4.1/iPhone',
525
+ 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.443692.0/iOS/14.8/iPhone',
520
526
  'Accept-Language': _options.acceptLanguage,
521
527
  'Accept-Charset': 'utf-8',
522
528
  'Connection': 'keep-alive',
@@ -547,7 +553,7 @@ function AlexaCookie() {
547
553
  } else if (error && (!_options || !_options.amazonPage)) {
548
554
  callback && callback(error, null);
549
555
  return;
550
- } else if (error && !_options.formerRegistrationData.amazonPage && _options.amazonPage) {
556
+ } else if (error && (!_options.formerRegistrationData || !_options.formerRegistrationData.amazonPage) && _options.amazonPage) {
551
557
  _options.logger && _options.logger('Continue with externally set amazonPage: ' + _options.amazonPage);
552
558
  } else if (error) {
553
559
  _options.logger && _options.logger('Ignore error while getting user data and amazonPage because previously set amazonPage is available');
@@ -569,7 +575,9 @@ function AlexaCookie() {
569
575
  loginData.localCookie = resData.cookie;
570
576
  loginData.csrf = resData.csrf;
571
577
  delete loginData.accessToken;
572
- _options.logger && _options.logger('Final Registraton Result: ' + JSON.stringify(loginData));
578
+ delete loginData.authorization_code;
579
+ delete loginData.verifier;
580
+ _options.logger && _options.logger('Final Registration Result: ' + JSON.stringify(loginData));
573
581
  callback && callback(null, loginData);
574
582
  });
575
583
  });
@@ -585,7 +593,7 @@ function AlexaCookie() {
585
593
 
586
594
  const exchangeParams = {
587
595
  'di.os.name': 'iOS',
588
- 'app_version': '2.2.223830.0',
596
+ 'app_version': '2.2.443692.0',
589
597
  'domain': '.' + amazonPage,
590
598
  'source_token': refreshToken,
591
599
  'requested_token_type': 'auth_cookies',
@@ -596,12 +604,12 @@ function AlexaCookie() {
596
604
  'app_name': 'Amazon Alexa',
597
605
  'di.os.version': '11.4.1'
598
606
  };
599
- let options = {
607
+ const options = {
600
608
  host: 'www.' + amazonPage,
601
609
  path: '/ap/exchangetoken',
602
610
  method: 'POST',
603
611
  headers: {
604
- 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.223830.0/iOS/11.4.1/iPhone',
612
+ 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.443692.0/iOS/14.8/iPhone',
605
613
  'Accept-Language': _options.acceptLanguage,
606
614
  'Accept-Charset': 'utf-8',
607
615
  'Connection': 'keep-alive',
@@ -650,7 +658,7 @@ function AlexaCookie() {
650
658
 
651
659
  });
652
660
  let localCookie = '';
653
- for (let name in cookies) {
661
+ for (const name in cookies) {
654
662
  if (!cookies.hasOwnProperty(name)) continue;
655
663
  localCookie += name + '=' + cookies[name] + '; ';
656
664
  }
@@ -678,26 +686,26 @@ function AlexaCookie() {
678
686
  initConfig();
679
687
 
680
688
  const refreshData = {
681
- "app_name": "ioBroker Alexa2",
682
- "app_version": "2.2.223830.0",
683
- "di.sdk.version": "6.10.0",
684
- "source_token": _options.formerRegistrationData.refreshToken,
685
- "package_name": "com.amazon.echo",
686
- "di.hw.version": "iPhone",
687
- "platform": "iOS",
688
- "requested_token_type": "access_token",
689
- "source_token_type": "refresh_token",
690
- "di.os.name": "iOS",
691
- "di.os.version": "11.4.1",
692
- "current_version": "6.10.0"
689
+ 'app_name': 'ioBroker Alexa2',
690
+ 'app_version': '2.2.443692.0',
691
+ 'di.sdk.version': '6.10.0',
692
+ 'source_token': _options.formerRegistrationData.refreshToken,
693
+ 'package_name': 'com.amazon.echo',
694
+ 'di.hw.version': 'iPhone',
695
+ 'platform': 'iOS',
696
+ 'requested_token_type': 'access_token',
697
+ 'source_token_type': 'refresh_token',
698
+ 'di.os.name': 'iOS',
699
+ 'di.os.version': '14.8',
700
+ 'current_version': '6.10.0'
693
701
  };
694
702
 
695
- let options = {
703
+ const options = {
696
704
  host: 'api.' + _options.baseAmazonPage,
697
705
  path: '/auth/token',
698
706
  method: 'POST',
699
707
  headers: {
700
- 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.223830.0/iOS/11.4.1/iPhone',
708
+ 'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.443692.0/iOS/14.8/iPhone',
701
709
  'Accept-Language': _options.acceptLanguage,
702
710
  'Accept-Charset': 'utf-8',
703
711
  'Connection': 'keep-alive',
package/lib/proxy.js CHANGED
@@ -3,7 +3,7 @@
3
3
  /* jshint strict: false */
4
4
  /* jslint node: true */
5
5
  /* jslint esversion: 6 */
6
- "use strict";
6
+ 'use strict';
7
7
 
8
8
  const modifyResponse = require('http-proxy-response-rewrite');
9
9
  const express = require('express');
@@ -27,7 +27,7 @@ function addCookies(Cookie, headers) {
27
27
  }
28
28
  }
29
29
  Cookie = '';
30
- for (let name in cookies) {
30
+ for (const name in cookies) {
31
31
  if (!cookies.hasOwnProperty(name)) continue;
32
32
  Cookie += name + '=' + cookies[name] + '; ';
33
33
  }
@@ -90,7 +90,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
90
90
  initialCookies.frc = _options.formerRegistrationData.frc;
91
91
  }
92
92
 
93
- if (!_options.formerRegistrationData || !_options.formerRegistrationData["map-md"]) {
93
+ if (!_options.formerRegistrationData || !_options.formerRegistrationData['map-md']) {
94
94
  initialCookies['map-md'] = Buffer.from('{"device_user_dictionary":[],"device_registration_data":{"software_version":"1"},"app_identifier":{"app_version":"2.2.223830","bundle_id":"com.amazon.echo"}}').toString('base64');
95
95
  }
96
96
  else {
@@ -123,7 +123,19 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
123
123
  // ignore
124
124
  }
125
125
 
126
- let proxyCookies = "";
126
+ function base64URLEncode(str) {
127
+ return str.toString('base64')
128
+ .replace(/\+/g, '-')
129
+ .replace(/\//g, '_')
130
+ .replace(/=/g, '');
131
+ }
132
+ function sha256(buffer) {
133
+ return crypto.createHash('sha256').update(buffer).digest();
134
+ }
135
+ const code_verifier = base64URLEncode(crypto.randomBytes(32));
136
+ const code_challenge = base64URLEncode(sha256(code_verifier));
137
+
138
+ let proxyCookies = '';
127
139
 
128
140
  // proxy middleware options
129
141
  const optionsAlexa = {
@@ -139,12 +151,12 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
139
151
  onProxyRes: onProxyRes,
140
152
  onProxyReq: onProxyReq,
141
153
  headers: {
142
- 'user-agent': "Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 PitanguiBridge/2.2.345247.0-[HARDWARE=iPhone10_4][SOFTWARE=13.5.1]",
154
+ 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 PitanguiBridge/2.2.345247.0-[HARDWARE=iPhone10_4][SOFTWARE=13.5.1]',
143
155
  'accept-language': _options.acceptLanguage,
144
156
  'authority': `www.${_options.baseAmazonPage}`
145
157
  },
146
158
  cookieDomainRewrite: { // enhanced below
147
- "*": ""
159
+ '*': ''
148
160
  }
149
161
  };
150
162
  optionsAlexa.pathRewrite[`^/www.${_options.baseAmazonPage}`] = '';
@@ -178,7 +190,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
178
190
  }
179
191
  }
180
192
  if (url === '/') { // initial redirect
181
- returnedInitUrl = `https://www.${_options.baseAmazonPage}/ap/signin?openid.return_to=https%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&accountStatusPolicy=P1&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.oa2=http%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fext%2Foauth%2F2&openid.oa2.client_id=device%3A${deviceId}&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.oa2.response_type=token&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.pape.max_auth_age=0&openid.oa2.scope=device_auth_access&language=${_options.amazonPageProxyLanguage}`;
193
+ returnedInitUrl = `https://www.${_options.baseAmazonPage}/ap/signin?openid.return_to=https%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&accountStatusPolicy=P1&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.oa2=http%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fext%2Foauth%2F2&openid.oa2.client_id=device%3A${deviceId}&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.oa2.response_type=code&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.pape.max_auth_age=0&openid.oa2.scope=device_auth_access&openid.oa2.code_challenge_method=S256&openid.oa2.code_challenge=${code_challenge}&language=${_options.amazonPageProxyLanguage}`;
182
194
  _options.logger && _options.logger('Alexa-Cookie: Initial Page Request: ' + returnedInitUrl);
183
195
  return returnedInitUrl;
184
196
  }
@@ -203,8 +215,8 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
203
215
 
204
216
  function replaceHosts(data) {
205
217
  //const dataOrig = data;
206
- const amazonRegex = new RegExp(`https?://www.${_options.baseAmazonPage}:?[0-9]*/`.replace(/\./g, "\\."), 'g');
207
- const alexaRegex = new RegExp(`https?://alexa.${_options.baseAmazonPage}:?[0-9]*/`.replace(/\./g, "\\."), 'g');
218
+ const amazonRegex = new RegExp(`https?://www.${_options.baseAmazonPage}:?[0-9]*/`.replace(/\./g, '\\.'), 'g');
219
+ const alexaRegex = new RegExp(`https?://alexa.${_options.baseAmazonPage}:?[0-9]*/`.replace(/\./g, '\\.'), 'g');
208
220
  data = data.replace(/&#x2F;/g, '/');
209
221
  data = data.replace(amazonRegex, `http://${_options.proxyOwnIp}:${_options.proxyPort}/www.${_options.baseAmazonPage}/`);
210
222
  data = data.replace(alexaRegex, `http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.${_options.baseAmazonPage}/`);
@@ -213,8 +225,8 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
213
225
  }
214
226
 
215
227
  function replaceHostsBack(data) {
216
- const amazonRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/www.${_options.baseAmazonPage}/`.replace(/\./g, "\\."), 'g');
217
- const alexaRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.${_options.baseAmazonPage}/`.replace(/\./g, "\\."), 'g');
228
+ const amazonRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/www.${_options.baseAmazonPage}/`.replace(/\./g, '\\.'), 'g');
229
+ const alexaRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.${_options.baseAmazonPage}/`.replace(/\./g, '\\.'), 'g');
218
230
  data = data.replace(amazonRegex, `https://www.${_options.baseAmazonPage}/`);
219
231
  data = data.replace(alexaRegex, `https://alexa.${_options.baseAmazonPage}/`);
220
232
  if (data === `http://${_options.proxyOwnIp}:${_options.proxyPort}/`) {
@@ -235,9 +247,9 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
235
247
  _options.logger && _options.logger('Alexa-Cookie: Headers: ' + JSON.stringify(proxyReq.getHeaders()));
236
248
  let reqCookie = proxyReq.getHeader('cookie');
237
249
  if (reqCookie === undefined) {
238
- reqCookie = "";
250
+ reqCookie = '';
239
251
  }
240
- for (var cookie in initialCookies) {
252
+ for (const cookie in initialCookies) {
241
253
  if (!initialCookies.hasOwnProperty(cookie)) continue;
242
254
  if (!reqCookie.includes(cookie + '=')) {
243
255
  reqCookie += '; ' + cookie + '=' + initialCookies[cookie];
@@ -258,7 +270,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
258
270
  let modified = false;
259
271
  if (req.method === 'POST') {
260
272
  if (typeof proxyReq.getHeader === 'function' && proxyReq.getHeader('referer')) {
261
- let fixedReferer = replaceHostsBack(proxyReq.getHeader('referer'));
273
+ const fixedReferer = replaceHostsBack(proxyReq.getHeader('referer'));
262
274
  if (fixedReferer ) {
263
275
  proxyReq.setHeader('referer', fixedReferer);
264
276
  _options.logger && _options.logger('Alexa-Cookie: Modify headers: Changed Referer: ' + fixedReferer);
@@ -318,11 +330,12 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
318
330
  _options.logger && _options.logger('Alexa-Cookie: Proxy catched parameters: ' + JSON.stringify(queryParams));
319
331
 
320
332
  callbackCookie && callbackCookie(null, {
321
- "loginCookie": proxyCookies,
322
- "accessToken": queryParams['openid.oa2.access_token'],
323
- "frc": initialCookies.frc,
324
- "map-md": initialCookies['map-md'],
325
- "deviceId": deviceId
333
+ 'loginCookie': proxyCookies,
334
+ 'authorization_code': queryParams['openid.oa2.authorization_code'],
335
+ 'frc': initialCookies.frc,
336
+ 'map-md': initialCookies['map-md'],
337
+ 'deviceId': deviceId,
338
+ 'verifier': code_verifier
326
339
  });
327
340
  return;
328
341
  }
@@ -363,7 +376,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
363
376
  app.get('/cookie-success', function(req, res) {
364
377
  res.send('<b>Amazon Alexa Cookie successfully retrieved. You can close the browser.</b>');
365
378
  });
366
- let server = app.listen(_options.proxyPort, _options.proxyListenBind, function() {
379
+ const server = app.listen(_options.proxyPort, _options.proxyListenBind, function() {
367
380
  _options.logger && _options.logger('Alexa-Cookie: Proxy-Server listening on port ' + server.address().port);
368
381
  callbackListening && callbackListening(server);
369
382
  callbackListening = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alexa-cookie2",
3
- "version": "3.4.3",
3
+ "version": "4.0.2",
4
4
  "description": "Generate Cookie and CSRF for Alexa Remote",
5
5
  "author": {
6
6
  "name": "Apollon77",
@@ -21,15 +21,17 @@
21
21
  "layla.amazon.de"
22
22
  ],
23
23
  "dependencies": {
24
- "cookie": "^0.4.1",
25
- "express": "^4.17.1",
26
- "http-proxy-middleware": "^1.2.0",
24
+ "cookie": "^0.5.0",
25
+ "express": "^4.18.1",
26
+ "http-proxy-middleware": "^2.0.6",
27
27
  "http-proxy-response-rewrite": "^0.0.1",
28
28
  "https": "^1.0.0",
29
29
  "querystring": "^0.2.1"
30
30
  },
31
31
  "devDependencies": {
32
- "@alcalzone/release-script": "^1.8.3"
32
+ "@alcalzone/release-script": "^3.5.9",
33
+ "@alcalzone/release-script-plugin-license": "^3.5.9",
34
+ "eslint": "^8.18.0"
33
35
  },
34
36
  "repository": {
35
37
  "type": "git",
@@ -41,6 +43,9 @@
41
43
  "scripts": {
42
44
  "release": "release-script"
43
45
  },
46
+ "engines": {
47
+ "node": ">=12.0.0"
48
+ },
44
49
  "main": "alexa-cookie.js",
45
50
  "readmeFilename": "readme.md"
46
51
  }
package/.commitmessage DELETED
@@ -1,3 +0,0 @@
1
- chore: release v3.4.3
2
-
3
- handle potential crash case (Sentry IOBROKER-ALEXA2-86)