Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

ANA Payを人力(+Cloudflareパワー)でマネーフォワードに連携する

最近よく旅行に行くようになったので、マイルをしこしこ貯めている。普段の買い物でもマイルを貯めたいが、航空会社のカードを作るほどでもない(というかもうカードはたくさんある)ので、ANA Payというスマホ決済サービスを使っている。

www.ana.co.jp

普通のGoogle Payとして使えるので、VISAが使える場所ならどこでも使えて嬉しい。オートチャージもある。

マネフォ ない

ところが、ANA Payを使うだけでは、単にオートチャージで引き落とされた情報しかマネフォには載ってこない。

マネフォはANA Payに対応していないのでこれはしょうがないのだが、しかしこれだとマネフォを使っている意味がない。困った。

人力連携

さて、完全に人力で連携するとなると、人間が手で家計簿を付けていた古墳時代へと逆戻りしてしまい、文明的ではない。あくまで我々は文明人であり、文明の力を使って便利に毎日を過ごしていたい。

我々の世界には、巨人の肩に乗るという言葉がある。すなわち、たいていの分野には先駆者がいるのだから、その成果に載っかって時間を節約しつつ、リスペクトしようという意味である。

なんと、ANA Payをマネフォに連携している先人がいるではないか。

github.com

しかしこれを手で動かすのはダルいので、今風のインフラに載っけて楽をしようと思う。

やりたいこと

さて、やりたいことといえば実は単純である。

  • 人間がANA Payで決済すると、ANA Payは決済情報をメールで寄越す
  • これをトリガーとしてブラウザを操作し、マネフォの画面をいじって手動で費目を入力させる

これだけである。

考えないといけないこと

これだけなのだが、考えることは実に多い。

  • メールをどうやってトリガーにするのか?
  • マネフォがメンテなどで使えず、トリガーが不発したらどうするのか?
  • どうやってブラウザを操作するのか?そのインフラをどこに配置するのか?

ありがたいことに、これらの要素の全部がCloudflareにあったので、今回はこれで楽をさせてもらうぞ。

当たり前だがこの手段はマネーフォワードの想定している使い方ではなく、何ら推奨されるものでもなく、自己責任である。非公式!

Cloudflare構成

メール受信

まずメールを受信してそれをトリガーにするには、Cloudflare Email Routingを利用する。

www.cloudflare.com

独自ドメインがあれば、ここにメールを転送させて、適当なWorkerを起動できるのだ。

ちなみに手持ちのドメインは全部別の用途に使っていて、DNSの設定が衝突することがわかったので、別途安いドメインを適当に購入した。節約のためのサービスを動かすためにお金を払っているが、これでいいのか?何も考えたくない。

次に、おなじみのCloudflare Workerでメールの内容をパースする。postal-mimeというnpmパッケージがあり、これを使うと日本語メールのbodyもデコードしてくれる。ANA Payが送ってくるメールは素朴なので、適当にregexでマッチすれば内容を抽出できる。ずっと素朴なままでいてほしい。

regexでデータを取り出したら、JSONにすれば元データの完成。

キューイング

マネフォのサービスはたまにメンテしている。このため、24時間かならず書き込みがうまくいくとは限らないので、キューイングしたい。ありがたいことに、Cloudflare Queuesというサービスがある。

developers.cloudflare.com

Queuesはバッチ処理やディレイをつけたリトライなどを利用できるので、この目的にぴったりだ。

Queuesでは、メッセージに.ack()したり.retry()したりするだけで勝手にあとはQueuesがやってくれる。

export default {
  async queue(batch, env) {
    for (const msg of batch.messages) {
      const parsed = PaymentSchema.safeParse(msg.body);
      if (!parsed.success) {
        console.error("Invalid message:", parsed.error.message);
        msg.ack();
        continue;
      }

      try {
        await processPayment(env, parsed.data);
        msg.ack();
      } catch (err) {
        console.error("Failed to process payment:", err);
        msg.retry();
      }
    }
  },
};

processしてからackするまでに何らかの原因でクラッシュしたらどうするのかといったことは、いったん考えないことにしている・・・

マネフォへの投稿

鬼門中の鬼門、ド鬼門である。ブラウザを手で操作して何かするなんて、Webエンジニアとしては一番やりたくない事のうちの一つだ。ちょっと前にCDP(Chrome DevTools Protocol)を使ってガチャガチャするコードを書いたことがあるけど、もうやりたくない。

またもやありがたいことに、CloudflareはBrowser Renderingというツールを提供している。

developers.cloudflare.com

これを使ってチビチビとidやclassを使って人力の入力を再現する。これ自体は難しくないのだが、マネーフォワードは2要素認証(2FA)を持っており、知らないIPからのアクセスはメールを使った2FAを要求するようになっている。

私は怠惰なので、2FAメールもWorkerに転送して内容をパースし、Cloudflare Workers KVに保存するようにした。ちょっとあまり上品ではない気がするけど、まぁ、そういうわけで・・・

developers.cloudflare.com

これはミニマルなKey-Value Storeで、こういう目的にぴったりだ。TTLも設定できる。

そんなこんなで自動的にログインして決済情報を入力できるようになった。無駄にエッジにデプロイされ、無駄に高級な環境で動いている。

まとめ

やったー。

先人をリスペクトし、ソースコードは公開しておきます。

github.com

と言いつつほとんどClaude Codeに書かせたのだよな。良い時代ですね

今後の課題

  • ほぼ毎回2FA喰らっているので、セッションを保持したい
  • 特に設定していないので、科目は未入力のままになる。いい感じにしたい
  • TypeScriptにしたい

マネーフォワードの皆様へ

  • ごめんね
  • APIを解放してくれ〜〜
★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?