Alexa-remote2でAlexaにログインできなくなった!【対処法】

スマートホーム
スポンサーリンク

注意

この記事はAlexa-cookie(v3.0.3)向けの記事です。最新版(v3.4.1)をお使いの方は、以下を参照下さい。

ちなみに、Alexa-cookieのバージョンは以下で確認できます。

$cd ~/.node-red
$npm list|grep alexa-cookie
│   ├─┬ alexa-cookie2@3.2.1

はじめに

Alexaをしゃべらせる(Node-red編)」や「Raspberry Piで最強の防犯カメラを作ってみる(動画記録・配信、動体検知・Line通知、顔検知・顔認証、Alexa搭載)[6/6]」でご紹介したように、我が家のスマートホームシステムでは、node-red-contrib-alexa-remote2を使って、Alexaをしゃべらせていました。

しかし、Alexa用のログインIDを新しいものに変えたところ、以下のようにログインができなくなってしまった😭 Node-redの画面には「Login unsuccessfull. Please check credentials.」というエラーが出ている。正常時は「Ready」。

原因:Amazon側の仕様変更

ネット上の情報を調査したところ、Amazon側の仕様変更によりユーザ&パスワードが動かなくなったとのこと。米国の「alexa.amazon.com」では、2019年夏頃から動かなくなったよう。。。日本の「alexa.amazon.co.jp」では、私の古いアカウントは使えていたので、アカウントによって、ログインできないアカウントがあるようです。

解決策:ログインをProxy認証に変更

私の調査結果では、node-red-contrib-alexa-remote2のログイン認証を「Email & Password」認証から「Proxy」認証に変更することで、解決できるらしい(後で分かるが、これだけでは解決できなかった)。

Alexa Accountノードの設定変更

Node-redのフロー上にある、Alexa Rutineノードをどれか一つ開きます。次に「Account」欄の鉛筆アイコンをクリックして「Alexa Accountノード」の設定画面を出し、以下のように設定します。
  Auth Method:Proxy
  This IP:※Node-redをインストールしているホストのIPアドレス
  Port:3456 ※デフォルトでOK
  Service Host:alexa.amazon.co.jp
  Page:amazon.co.jp
  Language:ja_JP

デプロイ

Proxy認証に変更したら「デプロイ」ボタンを押して、変更内容をデプロイしましょう。

デプロイが完了すると、Alexa Rutineノードの下に「Open 192.168.0.1:3456 in your browser」と表示されます。

ブラウザでアクセス

画面の指示通り、PCのWebブラウザで「http://192.168.0.1:3456/」にアクセスします。IPアドレスはnode-redホストのものに適宜変更してくださいね。すると、以下のようにAlexaのログイン画面が表示されるので、Amazonのユーザ名とパスワードを入力してログインします。ちなみに、2段階認証にしている人は、確認コードも入力が必要です。

ログイン

ログインが成功すると、以下の画面のようにCookieが取得できた旨が表示されます。

しかし、Node-redの画面に戻ってみると「Unexpected end of JSON input」とのエラーになってしまいます。。。ここからが長かった。。。。

Alexa-Cookie2のカスタマイズ

エラー原因を調べているとnode-red-contrib-alexa-remote2のCookie取得は、Alexa-cookie2というモジュールを利用していることが分かりました。

このモジュールのソースコードを読んでいくと、www.amazon.comにログインし、alexa.amazon.comからCookieを取得しているようです。日本語版のAlexaはalexa.amazon.co.jpでサービス提供されているので、alexa.amazon.comにはアカウントが無く、エラーとなっているようです。

そこで、このモジュールをamazon.co.jpに対応するようにカスタマイズして行きます。

alexa-cookie.jsの変更

alexa-cookie.jsに変更を加えていきます。

①alexa-cookie.jsを開く

Node-red起動ユーザのホームディレクトリの「.node-red/node_modules/node-red-contrib-alexa-remote2/node_modules/alexa-cookie2」にalexa-cookie.jsがあるので、これをバックアップ(コピー)して、開きます。

$cd ~/.node-red/node_modules/node-red-contrib-alexa-remote2/node_modules/alexa-cookie2
$cp alexa-cookie.js alexa-cookie.js.org
$vi alexa-cookie.js

②alexa-cookie.jsの変更

alexa-cookie.jsの494行目あたりに「host: ‘alexa.amazon.com’」の記載があるので、これを「host: ‘alexa.amazon.co.jp’」に変更します。

let options = {
   //host: 'alexa.amazon.com', //ここを書き換える
   host: 'alexa.amazon.co.jp', //ここを書き換える
   path: '/api/users/me?platform=ios&version=2.2.223830.0',
   method: 'GET',
   headers: {
      'User-Agent': 'AmazonWebView/Amazon Alexa/2.2.223830.0/iOS/11.4.1/iPhone',
      'Accept-Language': _options.acceptLanguage,
      'Accept-Charset': 'utf-8',
      'Connection': 'keep-alive',
      'Accept': 'application/json',
      'Cookie': Cookie
   }
};

proxy.jsの変更

次に、proxy.jsに変更を加えて行きます。

①proxy.jsを開く

alexa-cookie.jsがあるディレクトリ内の「lib」ディレクトリにproxy.jsがあるのでこれを開きます。

$cd lib
$cp proxy.js proxy.js.org
$vi proxy.js

②amazon.comの置換

proxy.js内にある「amazon.com」の記載を全て「amazon.co.jp」に変更します。結構数があるので、エディタの置換機能などを使うと良いと思います。

③alexa..amazon.co.jpの変更

proxy.jsの107行目にある「alexa..amazon.co.jp」(上で変更しているのでco.jpになってる)の記載を「alexa.amazon.co.jp」に変更(余分なドットを取る)します。これに気づくのに半日格闘しました💦

//optionsAlexa.pathRewrite[`^/alexa..amazon.co.jp`] = '';
optionsAlexa.pathRewrite[`^/alexa.amazon.co.jp`] = '';

④initialUrlの変更

www.amazon.comとwww.amazon.co.jpは少し仕様が違うようで、136行目あたりにある初期ページのURLを以下のように変更します。

//const initialUrl =  `https://www.amazon.co.jp/ap/signin?openid.return_to=https%3A%2F%2Fwww.amazon.co.jp%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios&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.amazon.co.jp%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}`;

const initialUrl =  `https://www.amazon.co.jp/ap/signin?showRmrMe=1&openid.return_to=https%3A%2F%2Falexa.amazon.co.jp%2F&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=amzn_dp_project_dee_jp&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&`;

⑤終了条件の変更

最後に、Cookie取得を判定する終了条件の変更を行います。proxy.jsの249行目に「/spa/index.html」の記述を追加して、このページが開かれたら終了するようにします。

if (
            (proxyRes.socket && proxyRes.socket._host === `www.amazon.co.jp` && proxyRes.socket.parser.outgoing && proxyRes.socket.parser.out
going.method === 'GET' && proxyRes.socket.parser.outgoing.path.startsWith('/ap/maplanding')) ||
            (proxyRes.socket && proxyRes.socket.parser.outgoing && proxyRes.socket.parser.outgoing._headers.location && proxyRes.socket.parse
r.outgoing._headers.location.includes('/ap/maplanding?')) ||
            (proxyRes.headers.location && proxyRes.headers.location.includes('/ap/maplanding?'))
            || (proxyRes.headers.location && proxyRes.headers.location.includes('/spa/index.html'))   //この一行を追加             
        ) {

変更は以上です。念のため、Nod-redを再起動しておきましょう。

参考までに、proxy.jsのdiffも載せておきます。

87c87
<         target: `https://alexa.amazon.com`,
---
>         target: `https://alexa.amazon.co.jp`,
106,109c106,109
<     optionsAlexa.pathRewrite[`^/www.amazon.com`] = '';
<     optionsAlexa.pathRewrite[`^/alexa..amazon.com`] = '';
<     optionsAlexa.cookieDomainRewrite[`.amazon.com`] = _options.proxyOwnIp;
<     optionsAlexa.cookieDomainRewrite['amazon.com'] = _options.proxyOwnIp;
---
>     optionsAlexa.pathRewrite[`^/www.amazon.co.jp`] = '';
>     optionsAlexa.pathRewrite[`^/alexa.amazon.co.jp`] = '';
>     optionsAlexa.cookieDomainRewrite[`.amazon.co.jp`] = _options.proxyOwnIp;
>     optionsAlexa.cookieDomainRewrite['amazon.co.jp'] = _options.proxyOwnIp;
124,127c124,127
<             if (url.startsWith(`/www.amazon.com/`)) {
<                 return `https://www.amazon.com`;
<             } else if (url.startsWith(`/alexa.amazon.com/`)) {
<                 return `https://alexa.amazon.com`;
---
>             if (url.startsWith(`/www.amazon.co.jp/`)) {
>                 return `https://www.amazon.co.jp`;
>             } else if (url.startsWith(`/alexa.amazon.co.jp/`)) {
>                 return `https://alexa.amazon.co.jp`;
129,132c129,132
<                 if (req.headers.referer.startsWith(`http://${_options.proxyOwnIp}:${_options.proxyPort}/www.amazon.com/`)) {
<                     return `https://www.amazon.com`;
<                 } else if (req.headers.referer.startsWith(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.amazon.com/`)) {
<                     return `https://alexa.amazon.com`;
---
>                 if (req.headers.referer.startsWith(`http://${_options.proxyOwnIp}:${_options.proxyPort}/www.amazon.co.jp/`)) {
>                     return `https://www.amazon.co.jp`;
>                 } else if (req.headers.referer.startsWith(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.amazon.co.jp/`)) {
>                     return `https://alexa.amazon.co.jp`;
136c136,137
<                 const initialUrl =  `https://www.amazon.com/ap/signin?openid.return_to=https%3A%2F%2Fwww.amazon.com%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios&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.amazon.com%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}`;
---
>                 //const initialUrl =  `https://www.amazon.co.jp/ap/signin?openid.return_to=https%3A%2F%2Fwww.amazon.co.jp%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios&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.amazon.co.jp%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}`;
> 		const initialUrl =  `https://www.amazon.co.jp/ap/signin?showRmrMe=1&openid.return_to=https%3A%2F%2Falexa.amazon.co.jp%2F&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.assoc_handle=amzn_dp_project_dee_jp&openid.mode=checkid_setup&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&`;
141c142
<         return `https://alexa.amazon.com`;
---
>         return `https://alexa.amazon.co.jp`;
154,155c155,156
<         const amazonRegex = new RegExp(`https?://www.amazon.com/`.replace(/\./g, "\\."), 'g');
<         const alexaRegex = new RegExp(`https?://alexa.amazon.com/`.replace(/\./g, "\\."), 'g');
---
>         const amazonRegex = new RegExp(`https?://www.amazon.co.jp/`.replace(/\./g, "\\."), 'g');
>         const alexaRegex = new RegExp(`https?://alexa.amazon.co.jp/`.replace(/\./g, "\\."), 'g');
157,158c158,159
<         data = data.replace(amazonRegex, `http://${_options.proxyOwnIp}:${_options.proxyPort}/www.amazon.com/`);
<         data = data.replace(alexaRegex, `http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.amazon.com/`);
---
>         data = data.replace(amazonRegex, `http://${_options.proxyOwnIp}:${_options.proxyPort}/www.amazon.co.jp/`);
>         data = data.replace(alexaRegex, `http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.amazon.co.jp/`);
164,167c165,168
<         const amazonRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/www.amazon.com/`.replace(/\./g, "\\."), 'g');
<         const alexaRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.amazon.com/`.replace(/\./g, "\\."), 'g');
<         data = data.replace(amazonRegex, `https://www.amazon.com/`);
<         data = data.replace(alexaRegex, `https://alexa.amazon.com/`);
---
>         const amazonRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/www.amazon.co.jp/`.replace(/\./g, "\\."), 'g');
>         const alexaRegex = new RegExp(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.amazon.co.jp/`.replace(/\./g, "\\."), 'g');
>         data = data.replace(amazonRegex, `https://www.amazon.co.jp/`);
>         data = data.replace(alexaRegex, `https://alexa.amazon.co.jp/`);
245c246
<             (proxyRes.socket && proxyRes.socket._host === `www.amazon.com` && proxyRes.socket.parser.outgoing && proxyRes.socket.parser.outgoing.method === 'GET' && proxyRes.socket.parser.outgoing.path.startsWith('/ap/maplanding')) ||
---
>             (proxyRes.socket && proxyRes.socket._host === `www.amazon.co.jp` && proxyRes.socket.parser.outgoing && proxyRes.socket.parser.outgoing.method === 'GET' && proxyRes.socket.parser.outgoing.path.startsWith('/ap/maplanding')) ||
247c248,249
<             (proxyRes.headers.location && proxyRes.headers.location.includes('/ap/maplanding?'))
---
>             (proxyRes.headers.location && proxyRes.headers.location.includes('/ap/maplanding?'))||
>             (proxyRes.headers.location && proxyRes.headers.location.includes('/spa/index.html'))

Cookieの取得

それではNode-redの画面に戻りCookieを取得しましょう。

①「デプロイ」ボタンのクリック

「デプロイ」ボタンを再度クリックします。

②Alexaにログイン

Webブラウザで「http://192.168.0.1:3456/」にアクセスしてAlexaにログインします。

③ノードの確認

Node-redの画面に戻って確認しましょう。今度は、ノードの下に「Ready」と表示されてノードが使えるようになりました。試しにちゃんと動作するか確認してみてください。

おわりに

今回はAmazonの仕様変更によってログインエラーが出るようになってしまったnode-red-contrib-alexa-remote2のとりあえずの対処方をご紹介しました。半日程度はちゃんと動いていますが、何か問題があったら記事を更新したいと思います。

また、この記事で紹介した内容は、alexa-cookieの開発者の方にもGithubで連絡済みなので、日本向けに修正してくれるかもしれません。alexa-cookieの修正が入るまでは手動で対処しましょう〜😃

関連記事

記事が参考になったら、ブログランキングに協力(クリック)して貰えると嬉しいです。

昼間はIT企業に勤めてますが、プライベートでは「育児×家事×IoT」をテーマに家のスマートホーム化に取り組んでいます。Androidアプリも作っているので使って下さい。質問・コメントは、↓のコメント蘭でもFacebookメッセンジャーでもどちらでも大丈夫です。
E-mail:naka.kazz.d@gmail.com

naka-kazzをフォローする
スマートホーム開発者向け
スポンサーリンク
naka-kazzをフォローする
スマートホーム×DIY

コメント

  1. はじめまして。
    大変勉強になる記事をいつもありがとうございます。
    今回、私のalexaも喋らなくなってしまい、上記を参考にnode-redの設定を変更したいと思いましたが、
    alexa-cookie.jsの場所がどうしても見つかりませんでした。
    ~/.node-red/node_modules/の下に node-red-contrib-alexa-remote2 が見当たりません。
    こちらの記事の[リビングに飾れる美しいスマートホームコントローラ]のnode-redインストール手順で設定しています。
    何かお分かりになることがあればお願いいたします。

    • コメントありがとうございます。node-red-contrib-alexa-remote2の場所ですが、node-redをroot起動しているため、以下にありませんでしょうか?
      /root/.node-red/
      上記に無い場合は、/home/root/.node-redに無いかもご確認ください。

      • 早速にありがとうございます。
        /home/root/.node-red/node_modulesの中にnode-red-contrib-alexa-remote2を見つける事ができました。
        でもその下に/node_modulesがありませんでした。
        ちなみに/home/root/.node-red/node_modulesの中に/alexa-cookie2/alexa-cookie.jsがあるのですが
        こちらを記事のとうりに設定してもエラーになってしまいました。
        私のraspiの環境(buster lite)がおかしいのかもしれませんね。

        • どのようなエラーになったか、教えていただければ分かるかもしれません。

          • ありがとうございます。
            http://192.168.1.5:3456にアクセスしてログインすると、

            続行するには、cookieを有効にしてください
            Amazon.jpでのお買い物を続けるには、Webブラウザのcookieを有効にしてください。
            ブラウザでcookieを有効にしたら、下にあるボタンをクリックして前のページに戻ってください。

            となってしまいます。
            ブラウザはedgeでcookieは有効になっています。chromeでも同じでした。

          • なるほど。。。初めてのケースですが、ブラウザを立ち上げwww.amazon.co.jpにアクセスしてログインしておき、
            そのまま新しいタブを開いてhttp://192.168.1.5:3456にアクセスしたらいかがでしょうか?

  2. ありがとうございます。
    amazonにログインした状態でも同じ状況でした。
    どうも私のレベルではこの辺が限界ですね。

  3. 大変参考になる記事を有難うございます。
    2020年6月21日現在、Alexa-remote2は3.2.0にずいぶん大幅に書き換えられて、’amazon.com’の直書きから ${.options.baseAmazonPage}に修正されています。この修正と同時かどうかわかりませんが、alexa-cookie.jsとproxy.jsの場所も変わっているようです。しかしながらまだamazon.co.jpからのcookie取得は上手くいかないようで、Node-redのAlexa RoutineでUnexpected end of JSON inputのエラーで引っかかっております。

    3.2.0対応の修正箇所をご教示いただけると幸いです。

    • ご連絡ありがとうございます。Alexa-remote2がバージョンアップしたんですね。alexa-cookeの開発者には連絡してあったので、修正してくれたのかもしれないです。ただ、amazon.co.jpからcookieが取得できないとのこと、次の週末に見てみますので、少々お待ち下さい。

  4. はじめまして、記事大変参考になりました。
    Alexa-remote2 v3.0.3近辺用ですよね?

    私もv3.0.9などで試して駄目で、
    v3.1.0にしたところpacificblueさんが仰っていた${.options.baseAmazonPage}に書き換えられておりましたので、
    v3.0.3に戻してから、記載が無かったのですがalexa-cookie.jsのamazon.comもamazon.co.jpに置換しました。(ここを置換すれば、もしかしたらv3.0.9でもいけるかもですが試してません)
    そしてデプロイの中のフローを再起動をすると繋がりました。
    フローを再起動しないと/spa/index.htmlからリダイレクトせず完了しませんでした。

    なおalexaが手元にない為しゃべったかの確認は取れておりません。

    v3.2.1までバージョンUPしているようですが、この辺のバージョンでの対応方法もpacificblueさんと同じく知りたいと思っております。
    お手数では御座いますがよろしくお願い致します。

  5. 度々申し訳ございません。
    オプションのFile Pathを入力して取得できるファイルの中身がnullとの文字列なのでクッキー自体は保存出来てないと思われます。

  6. はじめまして
    いつも記事を参考にさせて頂いてます。
    Alexa-remote2のamazon.co.jp対応についてですが、raspiを再起動した場合は
    再度、Webブラウザで「http://192.168.0.1:3456/」にアクセスしてAlexaに
    ログインが必要ですよね?
    raspiを常時稼働させてますが、たまにRebootしないと調子悪いです。
    crontabにて毎日定時Rebootしており、その際にchromedriverでブラウザを自動
    操作してログインさせようとしてますが、上手くいかないです。
    手動でchromedriverのブラウザ自動操作を走らせると、ログインできるのですが?
    ご教示頂けると有難いです。よろしくお願いします。