alexa-cookie2 5.0.0 → 5.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/README.md +14 -4
- package/alexa-cookie.js +4 -4
- package/example/example.js +8 -3
- package/lib/proxy.js +29 -25
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -16,13 +16,19 @@ If the automatic authentication fails (which is more common case in the meantime
|
|
|
16
16
|
|
|
17
17
|
Starting with version 2.0 of this library the proxy approach was changed to be more "as the Amazon mobile Apps" which registers a device at Amazon and uses OAuth tokens to handle the automatic refresh of the cookies afterwards. This should work seamless. A cookie is valid for 14 days, so it is preferred to refresh the cookie after 5-13 days (please report if it should be shorter).
|
|
18
18
|
|
|
19
|
+
## Troubleshooting for getting the cookie and tokens initially
|
|
20
|
+
If you still use the E-Mail or SMS based 2FA flow then this might not work. Please update the 2FA/OTP method in the amazon settings to the current process.
|
|
21
|
+
|
|
22
|
+
If you open the Proxy URL from a mobile device where also the Alexa App is installed on it might be that it do not work because Amazon might open the Alexa App. So please use a device or PC where the Alexa App is not installed
|
|
23
|
+
|
|
24
|
+
If you see a page that tells you that "alexa.amazon.xx is deprecated" and you should use the alexa app and with a QR code on it when you enter the Proxy URL" then this means that you call the proxy URL with a different IP/Domainname then the one you entered in the "proxy own IP" settings or you adjusted the IP shown in the Adapter configuration. The "proxy own IP" setting **needs to** match the IP/Domainname you use to call the proxy URL!
|
|
25
|
+
|
|
19
26
|
## Example:
|
|
20
27
|
See example folder!
|
|
21
28
|
|
|
22
29
|
* **example.js** shows how to use the library to initially get a cookie
|
|
23
30
|
* **refresh.js** shown how to use the library to refresh the cookies
|
|
24
31
|
|
|
25
|
-
|
|
26
32
|
## Usage
|
|
27
33
|
Special note for callback return for parameter result:
|
|
28
34
|
|
|
@@ -42,9 +48,6 @@ Please use the new method "refreshAlexaCookie" to refresh the cookie data. It ta
|
|
|
42
48
|
|
|
43
49
|
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
50
|
|
|
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
|
-
|
|
48
51
|
## Thanks:
|
|
49
52
|
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.
|
|
50
53
|
|
|
@@ -52,6 +55,13 @@ Partly based on [Amazon Alexa Remote Control](http://blog.loetzimmer.de/2017/10/
|
|
|
52
55
|
Thank you for that work.
|
|
53
56
|
|
|
54
57
|
## Changelog:
|
|
58
|
+
### 5.0.2 (2023-11-25)
|
|
59
|
+
* (Apollon77) Adjust some texts
|
|
60
|
+
|
|
61
|
+
### 5.0.1 (2023-11-24)
|
|
62
|
+
* (adn77) make registered device name configurable by Appname
|
|
63
|
+
* (Apollon77) Prevent some error/crash cases
|
|
64
|
+
|
|
55
65
|
### 5.0.0 (2023-09-08)
|
|
56
66
|
* IMPORTANT: Node.js 16 is now required minimum Node.js version!
|
|
57
67
|
* (Apollon77) Enhance registration process by also registering the app capabilities to allow usage of new HTTP/2 push connection
|
package/alexa-cookie.js
CHANGED
|
@@ -350,7 +350,7 @@ function AlexaCookie() {
|
|
|
350
350
|
}
|
|
351
351
|
if (_options.setupProxy) {
|
|
352
352
|
if (proxyServer) {
|
|
353
|
-
errMessage += `
|
|
353
|
+
errMessage += ` Please open http://${_options.proxyOwnIp}:${_options.proxyPort}/ with your browser and login to Amazon. The cookie will be output here after successfull login.`;
|
|
354
354
|
} else {
|
|
355
355
|
amazonProxy.initAmazonProxy(_options, prepareResult,
|
|
356
356
|
(server) => {
|
|
@@ -361,7 +361,7 @@ function AlexaCookie() {
|
|
|
361
361
|
if (!_options.proxyPort || _options.proxyPort === 0) {
|
|
362
362
|
_options.proxyPort = proxyServer.address().port;
|
|
363
363
|
}
|
|
364
|
-
errMessage += `
|
|
364
|
+
errMessage += ` Please open http://${_options.proxyOwnIp}:${_options.proxyPort}/ with your browser and login to Amazon. The cookie will be output here after successfull login.`;
|
|
365
365
|
callback && callback(new Error(errMessage), null);
|
|
366
366
|
}
|
|
367
367
|
);
|
|
@@ -386,7 +386,7 @@ function AlexaCookie() {
|
|
|
386
386
|
if (!_options.proxyPort || _options.proxyPort === 0) {
|
|
387
387
|
_options.proxyPort = proxyServer.address().port;
|
|
388
388
|
}
|
|
389
|
-
const errMessage = `
|
|
389
|
+
const errMessage = `Please open http://${_options.proxyOwnIp}:${_options.proxyPort}/ with your browser and login to Amazon. The cookie will be output here after successfull login.`;
|
|
390
390
|
callback && callback(new Error(errMessage), null);
|
|
391
391
|
});
|
|
392
392
|
}
|
|
@@ -442,7 +442,7 @@ function AlexaCookie() {
|
|
|
442
442
|
'domain': 'Device',
|
|
443
443
|
'app_version': apiCallVersion,
|
|
444
444
|
'device_type': 'A2IVLV5VM2W81',
|
|
445
|
-
'device_name': '%FIRST_NAME%\u0027s%DUPE_STRATEGY_1ST%
|
|
445
|
+
'device_name': '%FIRST_NAME%\u0027s%DUPE_STRATEGY_1ST%' + _options.deviceAppName,
|
|
446
446
|
'os_version': '16.6',
|
|
447
447
|
'device_serial': deviceSerial,
|
|
448
448
|
'device_model': 'iPhone',
|
package/example/example.js
CHANGED
|
@@ -8,12 +8,17 @@ const alexaCookie = require('../alexa-cookie');
|
|
|
8
8
|
|
|
9
9
|
const config = {
|
|
10
10
|
logger: console.log,
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
proxyOwnIp: '...', // required if proxy enabled: provide the own IP with which you later access the proxy.
|
|
12
|
+
// Providing/Using a hostname here can lead to issues!
|
|
13
|
+
// Needed to set up all rewriting and proxy stuff internally
|
|
14
|
+
|
|
15
|
+
// The following options are optional. Try without them first and just use really needed ones!!
|
|
16
|
+
|
|
17
|
+
amazonPage: 'amazon.de', // optional: possible to use with different countries, default is 'amazon.de'
|
|
18
|
+
acceptLanguage: 'de-DE', // optional: webpage language, should match to amazon-Page, default is 'de-DE'
|
|
13
19
|
userAgent: '...', // optional: own userAgent to use for all request, overwrites default one, should not be needed
|
|
14
20
|
proxyOnly: true, // optional: should only the proxy method be used? When no email/password are provided this will set to true automatically, default: false
|
|
15
21
|
setupProxy: true, // optional: should the library setup a proxy to get cookie when automatic way did not worked? Default false!
|
|
16
|
-
proxyOwnIp: '...', // required if proxy enabled: provide own IP or hostname to later access the proxy. needed to setup all rewriting and proxy stuff internally
|
|
17
22
|
proxyPort: 3456, // optional: use this port for the proxy, default is 0 means random port is selected
|
|
18
23
|
proxyListenBind: '0.0.0.0',// optional: set this to bind the proxy to a special IP, default is '0.0.0.0'
|
|
19
24
|
proxyLogLevel: 'info', // optional: Loglevel of Proxy, default 'warn'
|
package/lib/proxy.js
CHANGED
|
@@ -28,7 +28,7 @@ function addCookies(Cookie, headers) {
|
|
|
28
28
|
}
|
|
29
29
|
Cookie = '';
|
|
30
30
|
for (const name of Object.keys(cookies)) {
|
|
31
|
-
Cookie += name
|
|
31
|
+
Cookie += `${name}=${cookies[name]}; `;
|
|
32
32
|
}
|
|
33
33
|
Cookie = Cookie.replace(/[; ]*$/, '');
|
|
34
34
|
return Cookie;
|
|
@@ -175,7 +175,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
175
175
|
|
|
176
176
|
function router(req) {
|
|
177
177
|
const url = (req.originalUrl || req.url);
|
|
178
|
-
_options.logger && _options.logger(
|
|
178
|
+
_options.logger && _options.logger(`Router: ${url} / ${req.method} / ${JSON.stringify(req.headers)}`);
|
|
179
179
|
if (req.headers.host === `${_options.proxyOwnIp}:${_options.proxyPort}`) {
|
|
180
180
|
if (url.startsWith(`/www.${_options.baseAmazonPage}/`)) {
|
|
181
181
|
return `https://www.${_options.baseAmazonPage}`;
|
|
@@ -190,7 +190,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
190
190
|
}
|
|
191
191
|
if (url === '/') { // initial redirect
|
|
192
192
|
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}`;
|
|
193
|
-
_options.logger && _options.logger(
|
|
193
|
+
_options.logger && _options.logger(`Alexa-Cookie: Initial Page Request: ${returnedInitUrl}`);
|
|
194
194
|
return returnedInitUrl;
|
|
195
195
|
}
|
|
196
196
|
else {
|
|
@@ -201,12 +201,12 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
function onError(err, req, res) {
|
|
204
|
-
_options.logger && _options.logger(
|
|
204
|
+
_options.logger && _options.logger(`ERROR: ${err}`);
|
|
205
205
|
try {
|
|
206
206
|
res.writeHead(500, {
|
|
207
207
|
'Content-Type': 'text/plain'
|
|
208
208
|
});
|
|
209
|
-
res.end(
|
|
209
|
+
res.end(`Proxy-Error: ${err}`);
|
|
210
210
|
} catch (err) {
|
|
211
211
|
// ignore
|
|
212
212
|
}
|
|
@@ -239,18 +239,18 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
239
239
|
if (url.endsWith('.ico') || url.endsWith('.js') || url.endsWith('.ttf') || url.endsWith('.svg') || url.endsWith('.png') || url.endsWith('.appcache')) return;
|
|
240
240
|
//if (url.startsWith('/ap/uedata')) return;
|
|
241
241
|
|
|
242
|
-
_options.logger && _options.logger(
|
|
242
|
+
_options.logger && _options.logger(`Alexa-Cookie: Proxy-Request: ${req.method} ${url}`);
|
|
243
243
|
//_options.logger && _options.logger('Alexa-Cookie: Proxy-Request-Data: ' + customStringify(proxyReq, null, 2));
|
|
244
244
|
|
|
245
245
|
if (typeof proxyReq.getHeader === 'function') {
|
|
246
|
-
_options.logger && _options.logger(
|
|
246
|
+
_options.logger && _options.logger(`Alexa-Cookie: Headers: ${JSON.stringify(proxyReq.getHeaders())}`);
|
|
247
247
|
let reqCookie = proxyReq.getHeader('cookie');
|
|
248
248
|
if (reqCookie === undefined) {
|
|
249
249
|
reqCookie = '';
|
|
250
250
|
}
|
|
251
251
|
for (const cookie of Object.keys(initialCookies)) {
|
|
252
|
-
if (!reqCookie.includes(cookie
|
|
253
|
-
reqCookie +=
|
|
252
|
+
if (!reqCookie.includes(`${cookie}=`)) {
|
|
253
|
+
reqCookie += `; ${cookie}=${initialCookies[cookie]}`;
|
|
254
254
|
}
|
|
255
255
|
}
|
|
256
256
|
if (reqCookie.startsWith('; ')) {
|
|
@@ -260,9 +260,9 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
260
260
|
if (!proxyCookies.length) {
|
|
261
261
|
proxyCookies = reqCookie;
|
|
262
262
|
} else {
|
|
263
|
-
proxyCookies +=
|
|
263
|
+
proxyCookies += `; ${reqCookie}`;
|
|
264
264
|
}
|
|
265
|
-
_options.logger && _options.logger(
|
|
265
|
+
_options.logger && _options.logger(`Alexa-Cookie: Headers: ${JSON.stringify(proxyReq.getHeaders())}`);
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
let modified = false;
|
|
@@ -271,11 +271,11 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
271
271
|
const fixedReferer = replaceHostsBack(proxyReq.getHeader('referer'));
|
|
272
272
|
if (fixedReferer ) {
|
|
273
273
|
proxyReq.setHeader('referer', fixedReferer);
|
|
274
|
-
_options.logger && _options.logger(
|
|
274
|
+
_options.logger && _options.logger(`Alexa-Cookie: Modify headers: Changed Referer: ${fixedReferer}`);
|
|
275
275
|
modified = true;
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
|
-
if (typeof proxyReq.getHeader === 'function' && proxyReq.getHeader('origin') !==
|
|
278
|
+
if (typeof proxyReq.getHeader === 'function' && proxyReq.getHeader('origin') !== `https://${proxyReq.getHeader('host')}`) {
|
|
279
279
|
proxyReq.setHeader('origin', `https://www.${_options.baseAmazonPage}`);
|
|
280
280
|
_options.logger && _options.logger('Alexa-Cookie: Modify headers: Delete Origin');
|
|
281
281
|
modified = true;
|
|
@@ -286,7 +286,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
286
286
|
postBody += chunk.toString(); // convert Buffer to string
|
|
287
287
|
});
|
|
288
288
|
}
|
|
289
|
-
_options.proxyLogLevel === 'debug' && _options.logger && _options.logger(
|
|
289
|
+
_options.proxyLogLevel === 'debug' && _options.logger && _options.logger(`Alexa-Cookie: Proxy-Request: (modified:${modified})${customStringify(proxyReq, null, 2)}`);
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
function onProxyRes(proxyRes, req, res) {
|
|
@@ -296,9 +296,9 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
296
296
|
//_options.logger && _options.logger('Proxy-Response: ' + customStringify(proxyRes, null, 2));
|
|
297
297
|
let reqestHost = null;
|
|
298
298
|
if (proxyRes.socket && proxyRes.socket._host) reqestHost = proxyRes.socket._host;
|
|
299
|
-
_options.logger && _options.logger(
|
|
300
|
-
_options.proxyLogLevel === 'debug' && _options.logger && _options.logger(
|
|
301
|
-
_options.proxyLogLevel === 'debug' && _options.logger && _options.logger(
|
|
299
|
+
_options.logger && _options.logger(`Alexa-Cookie: Proxy Response from Host: ${reqestHost}`);
|
|
300
|
+
_options.proxyLogLevel === 'debug' && _options.logger && _options.logger(`Alexa-Cookie: Proxy-Response Headers: ${customStringify(proxyRes.headers, null, 2)}`);
|
|
301
|
+
_options.proxyLogLevel === 'debug' && _options.logger && _options.logger(`Alexa-Cookie: Proxy-Response Outgoing: ${customStringify(proxyRes.socket.parser.outgoing, null, 2)}`);
|
|
302
302
|
//_options.logger && _options.logger('Proxy-Response RES!!: ' + customStringify(res, null, 2));
|
|
303
303
|
|
|
304
304
|
if (proxyRes && proxyRes.headers && proxyRes.headers['set-cookie']) {
|
|
@@ -308,7 +308,7 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
308
308
|
}
|
|
309
309
|
proxyCookies = addCookies(proxyCookies, proxyRes.headers);
|
|
310
310
|
}
|
|
311
|
-
_options.logger && _options.logger(
|
|
311
|
+
_options.logger && _options.logger(`Alexa-Cookie: Cookies handled: ${JSON.stringify(proxyCookies)}`);
|
|
312
312
|
|
|
313
313
|
if (
|
|
314
314
|
(proxyRes.socket && proxyRes.socket._host === `www.${_options.baseAmazonPage}` && proxyRes.socket.parser.outgoing && proxyRes.socket.parser.outgoing.method === 'GET' && proxyRes.socket.parser.outgoing.path.startsWith('/ap/maplanding')) ||
|
|
@@ -324,8 +324,8 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
324
324
|
proxyRes.headers.location = `http://${_options.proxyOwnIp}:${_options.proxyPort}/cookie-success`;
|
|
325
325
|
delete proxyRes.headers.referer;
|
|
326
326
|
|
|
327
|
-
_options.logger && _options.logger(
|
|
328
|
-
_options.logger && _options.logger(
|
|
327
|
+
_options.logger && _options.logger(`Alexa-Cookie: Proxy catched cookie: ${proxyCookies}`);
|
|
328
|
+
_options.logger && _options.logger(`Alexa-Cookie: Proxy catched parameters: ${JSON.stringify(queryParams)}`);
|
|
329
329
|
|
|
330
330
|
callbackCookie && callbackCookie(null, {
|
|
331
331
|
'loginCookie': proxyCookies,
|
|
@@ -340,12 +340,12 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
340
340
|
|
|
341
341
|
// If we detect a redirect, rewrite the location header
|
|
342
342
|
if (proxyRes.headers.location) {
|
|
343
|
-
_options.logger && _options.logger(
|
|
343
|
+
_options.logger && _options.logger(`Redirect: Original Location ----> ${proxyRes.headers.location}`);
|
|
344
344
|
proxyRes.headers.location = replaceHosts(proxyRes.headers.location);
|
|
345
345
|
if (reqestHost && proxyRes.headers.location.startsWith('/')) {
|
|
346
|
-
proxyRes.headers.location = `http://${_options.proxyOwnIp}:${_options.proxyPort}
|
|
346
|
+
proxyRes.headers.location = `http://${_options.proxyOwnIp}:${_options.proxyPort}/${reqestHost}${proxyRes.headers.location}`;
|
|
347
347
|
}
|
|
348
|
-
_options.logger && _options.logger(
|
|
348
|
+
_options.logger && _options.logger(`Redirect: Final Location ----> ${proxyRes.headers.location}`);
|
|
349
349
|
return;
|
|
350
350
|
}
|
|
351
351
|
|
|
@@ -374,12 +374,16 @@ function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
|
374
374
|
app.get('/cookie-success', function(req, res) {
|
|
375
375
|
res.send(_options.proxyCloseWindowHTML);
|
|
376
376
|
});
|
|
377
|
+
if (_options.proxyPort< 1 || _options.proxyPort > 65535) {
|
|
378
|
+
_options.logger && _options.logger(`Alexa-Cookie: Error: Port ${_options.proxyPort} invalid. Use random port.`);
|
|
379
|
+
_options.proxyPort = undefined;
|
|
380
|
+
}
|
|
377
381
|
const server = app.listen(_options.proxyPort, _options.proxyListenBind, function() {
|
|
378
|
-
_options.logger && _options.logger(
|
|
382
|
+
_options.logger && _options.logger(`Alexa-Cookie: Proxy-Server listening on port ${server.address().port}`);
|
|
379
383
|
callbackListening && callbackListening(server);
|
|
380
384
|
callbackListening = null;
|
|
381
385
|
}).on('error', err => {
|
|
382
|
-
_options.logger && _options.logger(
|
|
386
|
+
_options.logger && _options.logger(`Alexa-Cookie: Proxy-Server Error: ${err}`);
|
|
383
387
|
callbackListening && callbackListening(null);
|
|
384
388
|
callbackListening = null;
|
|
385
389
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alexa-cookie2",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "Generate Cookie and CSRF for Alexa Remote",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Apollon77",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"layla.amazon.de"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"cookie": "^0.
|
|
24
|
+
"cookie": "^0.6.0",
|
|
25
25
|
"express": "^4.18.2",
|
|
26
26
|
"http-proxy-middleware": "^2.0.6",
|
|
27
27
|
"http-proxy-response-rewrite": "^0.0.1",
|
|
@@ -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.54.0"
|
|
35
35
|
},
|
|
36
36
|
"repository": {
|
|
37
37
|
"type": "git",
|