2017年12月19日火曜日

HTTP/1.1 Transfer-Encoding: chunked

Web Scraping 用のプログラムを組んでいて、HTTP レベルの Socket プログラムを自前で組むか、Client レベルの処理は言語環境のライブラリーに任せて HTML を解析・処理する程度のものを組むかという、二択問題によく悩む。これまでの経験上、後者の方が敷居が低く取りかかるのに容易であるというメリットがある。一方、一旦何らかの壁にぶち当たると、ブラックボックスのない前者の環境で試行錯誤を進めた方が、心理的にもまさしく“急がば回れ”の典型のような結果となり、トータルで楽になる。

そんなわけで、今回取り組んでいる物件についても、スタートアップは Java の URLConnection で一通り組み上げてしまって、それで問題なく全体的に動くものが出来上がっていたので、そのまま運用していたものだった。ゼロ状態からのスタートとなるプロジェクトでは、まずはどんな形であれ、全体としてちゃんと動くものへと到達できるかどうかが不明な状態なので、「まずは全体としてちゃんと動くもの」まで辿り着くことが何よりも重要である。そのためには、Client レベルのものは Java のコアライブラリーに任せて、Web Scraping にターゲットを絞った方が確実にプロジェクトを成功まで推進することができる。

それでそのまま動くようになったままで運用し続けていて、プログラムには手を入れていなかったのだが、今度、Lanterna を使って GUI 化したりして、使い勝手が向上したので、さらに前から欲しいと考えていた機能を追加したりした。最終的には GUI 化したらしたで CUI の時は気にならなかった処理速度が気になったので、ネットワークからのデータの読み込みをマルチスレッド化するところまで行き着いた。

このネットワーク読み込み処理のマルチスレッド化で、ある問題が表面化したのだった。

どうやら Java の URLConnection は、スレッドセーフではないようなのだ。とはいっても、このプロジェクトに関して言えば、Cookie がスレッド間で共有されていることが問題の核心であり、それを URLConnection 自体がスレッドセーフではないという話に含めていいのかどうかはわからない。ともかく、Cookie が上書きされてしまうのが原因で、サーバー側が付与する JSESSIONID に一貫性がなくなり、問題が発生することとなった。

URLConnection による Client 機能は Cookie なども宜しく処理してくれるので便利だが、一旦、Cookie を自前で操作したいとなると、逆に厄介だ。また、Apache のライブラリーを使えば、スレッドセーフに設計されているらしいが、こちらについては、Android の Java では Apache のネットワークライブラリーは非推奨であるという理由で、依存したくないので見送った。

そこで結局は HTTP レベルにフォールバックして Socket プログラムを自前で組むという方針にすることにした。

そもそも、Client レベルのものを言語環境のライブラリーに任せる場合の大きなメリットは

  1. Cookie を自前で処理する必要がなくなる
  2. HTTPS 対応を自前で行う必要がなくなる
  3. Transfer-Encoding: chunked を自前で処理する必要がなくなる

ではないかと思う。これまで、Cookie については面倒なだけで、必要に迫られた場合は、自前で HTTP レベルで処理する方策を採ってきた。HTTPS は調べてみたら SSLSocket を使えば Socket とほぼ同様に使えるので、意外と敷居は高くなかった。ところが chunked についてはお手上げで、自分が可能なことならば HTTP クライアントを自前で組むことを避ける主な理由はこれだった。

chunked の場合、HTTP/1.0 にして逃げることもできるので、無理に立ち向かう必要はない。ところで今回、HTTP/2.0 も使われ出したことだし、さすがに HTTP/1.0 に逃げるという消極的な方策はあまり気持の良いものでもないように感じた。それで今回は最後の壁である chunked へと立ち向かうことにした。

――で、chunked 対応な HTTP クライアントプログラムを自前で組んでみたのだが、なぜかセオリー通りに動作しない。何をやっても chunk のサイズ計算が合わないのである。レスポンスが Shift_JIS とかいう最悪の糞エンコーディングのせいだからかな? と思って色々試してみるも打破できない。行単位で処理する BufferedReader ではなく、 char 単位で処理する InputStreamReader で扱うようにしても改善せず。最後には byte 単位で処理する InputStream で直接扱っても改善しない。なぜかどうやっても、chunk サイズで指定された通りのサイズを読み込んでも、読み込まれるデータが chunk サイズよりも小さくなるのである。byte 単位なので、Shift_JIS による影響は完全に断てている。なのにこれは何なのか? 手は尽したのに、これではお手上げだ。

それでふと思い付いて chunk サイズをわざと +1000 してみたら、どうなるか試してみた。これが決定打だった。なんと chunk サイズを多くしても、全く読み込まれるデータが変わっていないのである。データが同じ場所でブツ切れている。

chunk サイズの問題ではないことに最後に行き着いて、それがどうやら、InputStream からのデータの読取に起因することだということが判明した。chunk サイズに相当する byte 配列を一つ用意して、それを inputStream.read(buffer) で一発で読み取ろうとしていたが、その処理でブツ切れになってしまっていたのだ。byte 配列を 1 バイト分だけ用意して、chunk サイズ分ループで回して 1 バイトずつ読み取ったら、完全に問題はクリアされた。

Java 以前には Perl がメインだったこともあって、ファイル IO 関係は一番感覚的に不慣れさが残っていたジャンルである。Perl の場合はデータはバイナリーモード(Java の byte に相当)か、文字モード(Java の char に相当)か程度で、一文字か文字列かという区別はなく、もちろん、バッファどうのということを気にすることもなく、とてもシンプルで苦労がなかった。そのため、Java を使うようになってからも、ファイル IO 関係は半ば「おまじない」的にコードを記述する感覚で、なぜ InputStream → InputStreamReader → BufferedReader と多段階になっているのか、不便な感じがする程度で深く検証することを避けていた。そのため、このようにデータの読み込みが半端な状況に陥いるなどというアイデアは最後になるまで想定できなかったのである。こういう経験で反対に、Perl の場合も、ファイル IO に関しては、while(<>) という記述をすることの由来がわかった。ところが Perl は大体が言語処理系側が宜くやってくれるので、記述上は配列に一気に読み込んでも、このようなブツ切れになってしまう羽目にはならなかったわけだが。Perl と比較すると、たまに C 言語の不便さが断片的に残っているのが Java なのかもしれない。それで Kotlin なんて話が出てくるのだろう。

2017年12月8日金曜日

Exception の使い処

Perl では Exception のことは気にしないでプログラミングできたので、Java で当初特異に感じたのが Exception の扱いだ。仕様に強制される形で try-catch を行う必要があるという認識で今まで凌いできた。

そもそも CUI でプログラミングしている段階では、例外処理については別段の配慮はせずとも、コンソールに JVM が吐くエラーメッセージが表示されるので、自分でエラーに備える処理を明示的にコーディングする必要はなかった。CUI というのはそういった意味でユーザーとプログラマーが完全に同一レベルの視点で体験を共有しているので、ある意味貴重な環境なのかもしれない。

そういった CUI の貴重な環境の習慣をそのまま引き摺ってしまっていて、GUI で Android のアプリなどを作っていても、例外処理について、標準メソッド側が要求するから受動的に try-catch を記述する程度で、自分から能動的に Exception クラスを用いるという経験があまりなかった。

ところで最近 Web のフォーム送信操作を自動化する Java プログラムを作成していて、想定外のエラーが発生した時、そのエラーがどの段階で出たエラーなのかということがわかった方が、自分自身で利用するだけでなくもしアプリを公開するという前提では、その方が良いと考えた。そこで、各段階で、想定通りではない結果になっていた場合、Exception を発生させるようなコードにすることにした。

当初は字義的に、RuntimeException を使っていた。ところがこれでも「どの段階で発生したのか?」がわかりにくかったので、最終的には IOException を使うことに落ち着いた。

GUI ライブラリーとして Lanterna という ncurses ライクなライブラリーを使っており、コンソールではなく、GUI の表示にエラーメッセージも表示させたいと考えた。当初の RuntimeException だと、どこかでエラーが発生していることがコンソールには表示されるのだが、どの段階で起ったのかが把握しにくく、GUI 側でもどこでキャッチすればいいのかがわかりにくい。そこで IOException にして、GUI 側で catch させることにしたのである。

ネットワークにアクセスしているので、標準ライブラリーからも IOException が発生する可能性があり、try-catch または throws 対応をしなくてはならない。これまで、throws の使い処がよくわからず、throws してもどの道さらにその上流の呼出元で catch しなければならなくなるだけで、いくらでも連鎖するので、とっとと catch した方がいい、と単純に考えていた。

ところが、今回のように例外はできるだけ GUI の層(MVC のうちの VC に相当)で処理することにすると、中核のフォームの送信などのネットワーク処理を行う層(MVC の M に相当)では例外はひたすら throws して呼出元に回した方がいいとわかった。標準ライブラリーから発生するものも throws し、また想定外の状態に陥った場合は throw new IOException() して throw する。catch するのは、Lanterna を使った GUI コードの層のクラスにおいて行う。そこで catch したエラーを GUI を通じてメッセージとして表示すればいい。

このようにしておくと、他のユーザーが使ってエラーが発生した時、エラーメッセージを表示してその情報を元にサポートする手掛かりを易くできる。

2017年11月8日水曜日

APFS は case-sensitive で

APFS を何も考えないでデフォルトのままフォーマットして macOS High Sierra をインストールして使っていたが、case-insensitive であることに気付いて、再度、SSD を完全に初期化し、case-sensitive フォーマット(非暗号化)にして、High Sierra をインストールし直した。

OS インストール後の各設定のカスタマイズや、基本ツールのインストールなどは、一度それぞれの方法を確立した後だったので、今回はそれらを通してメモにまとめておくことができた。FileZilla の設定 .xml はちゃんと iCloud ドライブに退避させておかなければならない、などの要点を整理するいい機会だった。

ちなみに、なぜ非暗号化でフォーマットしたかというと、一度暗号化でフォーマットしたのだが、OS のインストール後、暗号化されたドライブ用のユーザーアカウントが表示されるようになったので、気持悪かったので、非暗号化でフォーマットして仕切り直した次第である。OS のインストール完了後に、FileVault を有効化して暗号化したが、完全に暗号化が終わると、APFS のフォーマット自体が暗号化されたものに置き換った。ということは結局、最初から暗号化しておいた方が、時間的に遠回りしなくてスマートだったことになる(意味不明のユーザーアカウントはどうにか消す方法がある)。

2017年11月4日土曜日

QNAP の SSH のアクセス元制限の不完全な仕様

OpenVPN で実家の LAN につなぎ、VPN 経由で NAS(QNAP)にアクセスできるようになったので、ネットワークセキュリティを強化すべく、NAS の SSH にアクセス元制限を付けた。/root/.ssh/authorized_keys の公開鍵リストに、from="(ネットワークアドレス)" のオプション設定を追記したわけだ。

ところで、元々ブリッジモードの VPN 設定だったのを、ルーターモードに変更したため、アクセス元のクライアント機のネットワークアドレス(192.168.11.0/24)は NAS 側のネットワークアドレス(192.168.0.0/24)と異なるものとなった。そのため、from にカンマ(「,」)区切りでネットワークアドレスを列挙する必要がある。

from="192.168.0.0/24,192.168.11.0/24" ssh-rsa AAAAB3N...

しかし、どうやら QNAP の SSHd では仕様が不完全なようで、from として列挙したものを与えると、正常に動作しない(すべてのネットワークからアクセスできなくなった。仕方なく、一時的に telnet を使って復旧作業をする羽目になった)。

つまり、authorized_keys の from 設定としては列挙で設定することはできず、一種類の設定しか与えることができないのである。

簡単に思い浮ぶのは、VPN をルーターモードで運用するのをやめて、ブリッジモードに戻すことである。そうすれば、クライアント機のネットワークアドレスは NAS 側のネットワークアドレスと同一なので、from のエントリーは一種類で済む。

それでもせっかくルーターモードにしたのにブリッジに戻すのも何となく嫌だったので、(専門家でもないのに独学でネットワークエンジニアの資格をパスしたという“昔取った杵柄”を活用できたのか)ポク・ポク・ポク・チーンと思い付いたのが、ネットワークアドレスに、192.168.0.0/23 という値を使う方法。23 ビットというネットマスクを使う奇策である。この設定は、192.168.0.0 〜 192.168.1.255 の範囲の IP を意味するネットワークアドレスである。

from="192.168.0.0/23" ssh-rsa AAAAB3N...

従って、OpenVPN の設定においても、ルーターモードで使うネットワークアドレスを、192.168.11.0/24 から、192.168.1.0/24 に変更し、さらに、VPN サーバーや NAS の所属するネットワーク(192.168.0.0/24)側のゲートウェイとなるルーターの静的ルーティングの設定に 192.168.1.0/24 へのゲートウェイが VPN サーバーであることを設定し直す。

これで NAS の SSHd を再起動し、VPN に接続し直し、ssh がログイン可能であることを確認できた。ただし、ssh そのものと scp は SSHd の再起動で上手く行ったが、sftp は SSHd の再起動では駄目で(おそらく独立した別個の daemon なのだろう)、NAS 自体を再起動する羽目になった(もしかしたら、管理画面の SFTP を有効にするを OFF(適用)→ ON(適用)するだけで良かったかもしれない)。


※ちなみに、僕の環境では QNAP の NFS の(共有フォルダ)設定でもアクセス制限を行っていたので、ここの設定も 192.168.0.0/23 に直した。

2017年10月28日土曜日

OpenVPN を TAP(ブリッジ)→ TUN(ルーター)へ変更

基本的に VPN と NFS を使った利用環境は構築できたので、最後に少しでも VPN を最適化しておきたくなり、OpenVPN のモードを TAP(ブリッジ)から TUN(ルーター)へ変更することにした。

.ovpn

まずはサーバー(DD-WRT)側と、クライアント側(Mac、Linux)双方で、.ovpn 中の dev 設定を tap から tun に変えることが基本となる。

dev tun

クライアント側はこれだけで他にやることはない。一方、サーバー側ではルーターモード体制に伴ういくつかの副作用的な状況を解決するための設定が必要となる。

サーバー(DD-WRT)側

設定中で tun にする以外に、VPN 専用のサブネットの設定が必要になる。DD-WRT の設定の、TUN / TAP を選択する直下の Network と Netmask の部分がそれである。ここの例では 192.168.11.0/24 としてみた。

ブリッジモードではクライアントはそのままサーバー側のサブネット(192.168.0.0/24 とする)に参加する形となり、VPN サーバーが DHCP サーバーとしてクライアントに IP プールの中から一つ割り当てる形だった。ルーターモードでは、VPN 用のサブネット(192.168.11.0/24)丸ごとが IP プールとなりそれをクライアントに割り当てる。なので、VPN クライアントはサーバー側の本来のサブネットには直接参加しない形となるので、VPN 用のサブネットからサーバー側の本来のサブネットへとアクセスするためのルーティング設定が必要となる。そのために、DD-WRT の Additional Config においてクライアントにプッシュする形でルーティング設定をセットする。

push "redirect-gateway def1 bypass-dhcp"

※ "route 192.168.11.0 255.255.255.0" を別途 push する必要はない。redirect-gateway でリダイレクトされる Gateway 設定に同じ route 情報は含まれている。

さらに、これで VPN サブネット側のクライアントがサーバー側の本来のサブネットにアクセスできるようになったが、反対にサーバー側の本来のサブネット(192.168.0.0/24)の機器から VPN クライアントの属する VPN サブネット(192.168.11.0/24)側にアクセスできるようにもする必要がある。

このために、サーバー側のブロードバンドルーター(192.168.0.1 とする)の設定で、静的ルーティング設定として 192.168.11.0/24 のゲートウェイが DD-WRT の稼動する VPN サーバー(192.168.0.2 とする)であることを設定する。


以上で、ルーターモードで正常に稼動するようになった。OpenVPN では一般にルーターモード(TUN)が推奨されているように思われるが、まず体制を確立するのが簡単なのはブリッジモード(TAP)だと思うので、初めて挑戦する人にはブリッジモードで試すことをお勧めする。一方、レイヤー 2 の余計なパケットが流れなくなるので、トラフィック的にはルーターモードの方がより安定していることは確かである。

ローカルディスク ⇄ NFS ディスク間の rsync

前回で OpenVPN の接続と NFS のマウントまで自動化できたので、あとは特定のフォルダーをローカルディスク ⇄ NFS ディスク間における rsync をボタン一発でできるようにするだけだ。

最新の rsync

macOS 標準の rsync はバージョンが旧いので、Homebrew で最新バージョンにするのが常套のようだ。

brew install rsync

だけで ok。brew tap してからという情報は既に古いものなので注意。

OS 標準の元から存在する rsync は /usr/bin/rsync に、brew でインストールされた新しい rsync は /usr/local/bin/rsync にある。

ローカルディスク ⇄ NFS ディスク間における rsync

下の例では、~/eclipse-workspace フォルダを丸ごと、NFS にマウントした NAS の共有フォルダにバックアップしている。また、NAS 側で NFS のオプションを ALL_SQUASH で自分のアカウント名に割り当てているため、ファイルの所有者などの情報は rsync 側のオプションで制御していない。rsync 自体の詳しいオプションについては別途詳細を調べて欲しい。また下の例では省略したが、実際には --exclude オプションなども指定して、キャッシュデータは一々バックアップしないように等している。

/usr/local/bin/rsync -ruv --delete ~/eclipse-workspace /Volumes/NFS

Automator によるアプリ化

上記 rsync のコマンド内容のシェルスクリプトを Automator を使ってアプリ化する。

Automator の使い方自体については簡潔な解説があり参考になる。

2017年10月27日金曜日

VPN 接続(Tunnelblick)と NFS マウントの自動化

先の記事で sudo がパスワード入力なしで実行できるようになったので、それを前提として VPN 接続に連動して NFS のマウント/アンマウントを自動化する方法を確立した。

(Tunnelblick のベースである)OpenVPN 自体の仕様で .ovpn ファイルの設定で up / down 用のスクリプトを指定できるようになっている。この仕様に加えて、Tunnelblick では、connected.sh と pre-disconnect.sh という名前のスクリプトをそれぞれ up / down 用スクリプトとして割り当てることによって「接続後」「切断前」に実行するスクリプトとし扱ってくれるようだ。

なので、connected.sh と pre-disconnect.sh を用意し、それぞれにおいて、NFS をマウント/切断する処理を記述しておいた。

connected.sh

#!/bin/sh
sudo mkdir /Volumes/NFS
sudo mount_nfs -P 192.168.0.1:/share /Volumes/NFS

pre-disconnect.sh

#!/bin/sh
sudo umount /Volumes/NFS

※ umount 時に /Volumes/NFS は自動的に rmdir されるので、rmdir は明示的に行う必要はない。

以上の 2 種のスクリプトを用意した上で、.ovpn に

.ovpn

up ~/OpenVPN/connected.sh
down ~/OpenVPN/pre-disconnect.sh

といったような形式の設定を追加する。

最後に、Tunnelblick で .ovpn をインポートする。これだけである。

※ .ovpn や .sh を修正した場合、都度 Tunnelblick にインポートし直す必要がある点に注意する。Tunnelblick はインポート時に自前で .ovpn や .sh をコピーしてそれを直接使うので、インポート元の .ovpn や .sh を修正しただけでは Tunnelblick の挙動に反映されない。


Mac から NFS を使ってみた結果……

iCloud ドライブや Google ドライブのような感覚で使いたいと思って、VPN を構築し、VPN 経由で NAS に接続して NFS を使う──というのが元々の目的だった。これでできるようになったわけだが、実際に Eclipse で NAS にある作業ディレクトリーを使ってみたところ……重い。

というわけで、NAS を使ったクラウドドライブ化作戦は諦め、素直にローカルの作業ディレクトリーを使って、適宜 NAS にバックアップする体制にすることにした。つまり、rsync を使って、ローカル(Mac)のディレクトリとマウントした NFS の間でプットする。どの道、iCloud にせよ Google ドライブにせよ、クラウドストレージは実際そのような形式をとっているわけであって、常に NAS のストレージ上のファイル実体を直接読み書きしているわけではない(そうでないと、クラウドストレージはオフライン時に利用できない)。もちろん、クラウドストレージの場合はプットだけではなくプルも同程度行われることを前提としており、さらに他人との共有なども考えられている。しかし、僕が考えていた使い方に関しては、基本的にプッシュの一方通行だから、rsync だけ一発で行えるスクリプトなり、Automator アプリなりを用意しておけば済み、それが iCloud や Google ドライブで有料で大容量を使った場合と何ら差異はないという話である。

2017年10月26日木曜日

sudo のパスワード入力を省略できるようにする

OpenVPN で、接続確立後に自動で NFS をマウントし、接続切断時(直前)に NFS をアンマウントするシェルスクリプトを使おうと思った。ところが、mount / umount には root 権限が必要なので、通常では sudo するのにパスワード入力が求められてしまう。

色々調べた結果、/etc/sudoers という設定ファイルによって制御が可能であり、さらに sudoers を編集するのには危険が伴うので、visudo を通じて編集するのが常識的だということがわかった。

macOS / Linux のいずれにおいても、基本的には

%admin ALL=(ALL) ALL

となっている部分を

%admin ALL=(ALL) NOPASSWD:ALL

とすればよい。これは管理者グループに所属するユーザーを対象に、sudo コマンドの実行時にパスワードを不要とする設定である。(また、このようにグループの設定からアプローチするやり方ではなく、個々のユーザー単位で同様の設定をするアプローチでも可能である)

注 1:エントリーの順番

Mac では root と %admin しか元々エントリーがなかったので、気にする必要はなかったが、Linux(Ubuntu GNOME 16.04LTS)では root / %admin / %sudo となっていて、グループのエントリーが %admin と %sudo の 2 種類あった。この状態で %admin のエントリーを NOPASSWD にしても %sudo のエントリーで上書きされてしまうので、エントリーの順序を入れ替えて、%sudo の後に %admin のエントリーが来るように編集しなければならない。

注 2:Ubuntu GNOME 16.04LTS での管理者グループ ID

Ubuntu GNOME 16.04LTS では管理者グループの ID が admin ではなく、adm であった。にもかかわらず、sudoer のエントリーは %admin となっていたため、%adm と修正する必要があった。

注 3:visudo

visudo はその名の通り、vi がベースになっているので、操作がよくわからない場合は vi の情報を調べてみるとよい。

2017年10月25日水曜日

SSH の公開鍵認証+IP制限

過去に NAS(QNAP)の SSH の設定を色々いじっている時にも SSH について触れたことがあったが、その時は rsync の環境を構築しようとしていた記事の中で SSH も含めていたため、なぜ SSH 単独の話題ではなかったのかという事情についてまでは忘れていた。その時の本目的はあくまでも NAS を使ったデータのバックアップ環境の確立だったので、SSH 自体は使っても使わなくてもよかったからだ。

その当時においては、当初、VPN から NAS にアクセスして、NFS を使う方策を試みたが、VPN が PPTP を使ったセキュリティ的に脆弱なものであり、SSH によって rsync ができるようになったので、VPN も NFS も忘れていた。ところが、今現在、OpenVPN でセキュリティ的に十分な環境が整い、Mac から VPN 経由で NAS をクラウド的に利用する方法を模索し始めてみると、Samba よりも NFS の方がちゃんと動くし、Windows 抜きで Mac か Linux かで動かすのだから、よりによって(本来 Windows ちゃんと仲良く戯れるための)Samba など使わないに越したことはないのだ。

ともかく、VPN 前提で考えてみると QNAP の SSH のセキュリティも改めてちゃんと見直したくなり、アクセスを LAN からのアクセスに制限できないかと調べてみると、ちゃんと方法があったので、早速そうした。方法はサーバー(QNAP)側 .ssh/authorized_keys のエントリーに、from="192.168.0.0/24" のような形式のオプションを追加することである。次のような感じで:

from="192.168.0.0/24" ssh-rsa AAAAB3...AgRiOf my Ubuntu
from="192.168.0.0/24" ssh-rsa AAAAB3...v17zrd my Macbook

こうすることで、SSH は LAN 内からの接続しか受け付けなくなった。


注 1: VPN 経由での接続

OpenVPN を使ってアクセスする際、ssh admin@192.168.0.1 のように、IP アドレスで NAS にアクセスする必要がある。myqnapcloud.com の方を使うと IP アドレスは当然グローバルアドレスになってしまうので、アクセスを拒絶される。

注 2: 公開鍵の作成

過去記事でも触れたが改めてここでもまとめておく。コマンドは:

ssh-keygen -t rsa -C "作成するキーペアに関するコメント情報"

どちらかというとパスフレーズは使わなくてもよい。

注 3: 公開鍵の QNAP NAS への配置

scp か sftp を使ってアップロードする。QNAP の場合、SSH や scp、sftp でログインした場合のホームは /root である。/share/homes/admin ではない。authorized_keys は /root/.ssh/authorized_keys として配置することになる。GUI の File Station で操作できる相手ではない点に留意する。

注 4: ssh/scp/sftp

ssh と scp/sftp とではポート(以下の例では 50022)の指定の指定方法に大文字小文字の違いがある。

ssh -p 50022 admin@192.168.0.1
scp -P 50022 (ローカルパス) admin@192.168.0.1:(サーバー側のパス)
scp -P 50022 admin@192.168.0.1:(サーバー側のパス) (ローカルパス) 
sftp -P 50022 admin@192.168.0.1

Mac の OpenVPN クライアント(Tunnelblick)

Mac での OpenVPN クライアントとしては Tunnelblick というものがメジャーなようなので、これを使うことにした。

設定ファイル自体は、Linux での OpenVPN の場合の .ovpn を使う点は全く同じなので、Linux 上で証明書類を作成し、それをベースに証明書の内容をコピー&ペーストで埋め込んだ形での .ovpn ファイルを作成した。

Linux でのクライアント用の .ovpn との唯一の違いは、Mac では user nobody と group nobody の設定を使わずにコメントアウトした点のみである(Mac ではこの設定があるとエラーが出る)。

それ以外は基本的にサーバー側設定に依存する設定なので、何ら Linux 用のものと変わる点はない。

こうやって用意した .ovpn を Tunnelblick に読み込ませてしまえば、あとは Tunnelblick で接続ボタンを押すだけで自在に VPN に接続できるようになった。

補足

VPN の接続の度にクライアントのグローバル IP が不明でどうのというメッセージが表示される。これは VPN 非接続時のグローバル IP から、VPN 接続時のプライベート IP へと IP が変化して VPN に接続したことを検知する機能に関するのなので、VPN 接続自体の問題は無関係である。僕の場合、VPN 非接続時の通常の通信状況においても、WiMAX ルーター経由でネットを利用しているので、Mac 自体は WiMAX ルーター下のプライベート IP が割り当てられている。なので、このメッセージを回避するには、グローバル IP の変化を検知する機能を off にすればよい。Tunnelblick の以下のチェックを on にすれば当該機能を off することができる。

2017年10月24日火曜日

VPN 環境の OpenVPN 化

Mac をいじり出して、iCloud を軸にした標準アプリの設計思想が非常に気に入ってしまった。一般のユーザー視点なら無料 5GB で十分である。

ところが、Mac をメイン機とするならば、僕の場合、エンジニア(プログラマー)的側面も、一般ユーザーとしての立場に加えて必要になってくる。外にも持ち歩く MacBook に、開発中のデータが入っているのは非常にリスクが高いから、データの保管場所が MacBook の実機に依存するのは避けたい。だが、アプリを開発するためのプロジェクトファイルを iCloud ドライブにぶち込んでしまうと、どうやってもすぐに無料で利用できる 5GB の限界に達してしまう。かといって課金までして iCloud を増量したいとも思わない。

となると、せっかく実家で運用している QNAP 製の NAS があるので、それを使って iCloud のような運用ができないかと考えた。これまではデータを随時バックアップするという用途に NAS を使っていたのだが、クラウド的に、データ本体を常に NAS 側に置いておいて、それを端末側で参照するという形である。

ところが、写真などのマルテメディアデータはそのような専用のアプリが存在するのだが、ファイル一般となると iCloud ドライブのような使い方のできるオープンなアプリが存在しない。iCloud ドライブは macOS 専用だし、Google Drive にしても専用アプリをインストールする必要があり、それも Windows と macOS のみで Linux では使えない。

また、昔からある SMB の場合、LAN での利用を前提としていて、クラウドよりも一昔前のスタイルのまま停滞している感がある。

WebDAV

選択肢が限られていたので、まず最初に QNAP NAS で使える WebDAV を使ってみることにした。これは、macOS でも Linux でも標準で使えて、ネットワークドライブとして iCloud ドライブや Google Drive のようにアクセスが可能である。

ところが、WebDAV にはバグがあり、それは WebDAV が依存している apache のバグに由来するようだが、フォルダに index.html のファイルが存在すると、そのフォルダが空っぽ状態でファイルのリストが見えなくなってしまうという問題が発生した。

また、反応速度のせいか、例えば Eclipse で work_space として WebDAV 経由のフォルダを指定すると、エラーが出て、使えないことが判明した。

以上から、WebDAV によるクラウドドライブの実現は諦めた。

VPN + SMB

こうなったらオーソドックスに SMB を使ってみるしかないと思い、そのために VPN を構築することにした。元々、実家のルーターの設定などをリモートでメンテナンスするために、PPTP を使った VPN サーバーは立てていた。古い Buffalo のルーターを DD-WRT 化したものを使っている。しかし、最近 PPTP がどうも不安定化しすぐに接続が切れる。それに PPTP は技術的に世間で非推奨であり、OpenVPN を使うべきなのはほとんど常識である。設定の手間があったので OpenVPN を避けてきたが、クラウドドライブ実現のためにはちゃんと OpenVPN 化するべきだと思って、今回チャレンジすることにした。

OpenVPN

基本的に作業は Ubuntu (16.04LTS) 上で行った。一般に Linux 用の OpenVPN についてネット上で見つけられる情報は、サーバー用とクライアント用がセットになった解説だが、僕の場合は、サーバー側は DD-WRT で運用するので、Linux についてはクライアントとしての使い方になる。とはいえ、認証局(CA)として各証明書ファイルを作成するのは同じ Ubuntu マシン上で行うので、openvpn パッケージをインストールしなければならないのはサーバーとして運用する場合と同じである。基本的に How To Set Up an OpenVPN Server on Ubuntu 16.04 という英語の解説の通りに従い上手く行った。

作業として必要なことは

  1. 認証局(CA)として各証明書ファイル(秘密鍵含む)を作成すること
  2. クライアント用の設定ファイルを作成すること

の 2 つである。サーバーは DD-WRT の機能を使うので、主に DD-WRT の GUI で各証明書ファイルの内容をセットすればいい。解説に従って作成したいくつかの証明書と秘密鍵の内容をコピー&ペーストした。また、ネットでは TUN を使う例が多かったが、TAP にした。DD-WRT では AES-512-CBC も選べるようになっていたが、Ubuntu 側が対応していないようだったので、AES-256-CBC で我慢することにした。

クライアント側としては、先程クライアントマシン上で作成したクライアント用各証明書ファイルを使った設定ファイルを作成をするスクリプトを解説ページが用意してくれているので、それを使って作成した。ただし、DD-WRT 側の設定に合わせて、dev tap や cipher、auth などは手動でカスタマイズする必要はあるだろう。

ポートマッピングを忘れずに

初めての作業だったので、解説ページに沿ってやったものの、最初は接続が失敗した。実は、OpenVPN サーバー(DD-WRT)側ネットワークのポートマッピングで、UDP 1194 を通す設定を行っていなかっただけであった。運良く、検索一発目でポートマッピングが原因で失敗するのが一番多いと書かれている OpenVPN の FAQ を見つけることができ、すんなり解決できた。

GNOME のネットワーク設定(Network Manager)

不安定化していた PPTP と比べて、OpenVPN で接続が確立されると非常に安定している。だが、ターミナルでコマンドを使って OpenVPN を動かしている形なので、PPTP の場合のように、GNOME の画面右上のネットワーク設定を使った GUI で使えるようにできないかと思って調べたら、流石は Linux、流石は GNOME。ありました。apt install network-manager-openvpn-gnome するだけ。これで新規のネットワーク接続設定を追加すると VPN ではファイルからのインポートを選べるので、上の作業で作成した .ovpn ファイルを選択すれば、あとは各種設定は自動でセットされる。流石!


Ubuntu 環境で安定に接続が確立できることは確認できた。これで Mac でも OpenVPN をセットアップし、さらに SMB でクラウド化した状態で、Eclipse などが使えるかどうかというチャレンジは、また次の機会に。


補足 1

VPN 経由で LAN にアクセスするには以上で十分だが、さらに LAN の内側からインターネットに出たい場合、DD-WRT 側で追加の設定が必要だった。Additional Config 欄に

push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 192.168.0.1"
push "dhcp-option DNS 8.8.8.8"

という形で、クライアント側のネットワーク設定のデフォルトゲートウェイを(VPN 接続時に)上書きして必ず VPN 経由でインターネット側に出るようにし、さらに DNS サーバーのアドレスも指定しておく。

補足 2

OpenVPN のメッセージを見ていると、MTU の数値がサーバー⇔クライアント間で矛盾しているという警告が出ているので、色々と MTU 関係を調整した。

まず、実家は au ひかりであり、自分は WiMAX2+ なので、いずれも MTU は 1500 という理想的な環境である(ちなみに NTT の Flet's では PPPoE に加えて他にも余計なヘッダが入るため MTU は 1454 となる)。しかし、WiMAX ルーターの設定で MTU が設定できるようになっているが、なぜかデフォルトでは 1500 よりも低くしてあったので、ちゃんと 1500 にしておく必要があった。さらに、OpenVPN を運用するサーバー(DD-DRT)側もデフォルトで Tunnel MTU setting が 1400 にしてあったので、ちゃんと 1500 にする必要があった。Tunnel UDP Fragment は空欄(デフォルト)、Tunnel UDP MSS-Fix は無効(デフォルト)のままでよい。

以上で、OpenVPN をオンにしてもオフにしてもいずれも、ping コマンドで 1472 バイトのパケットがギリギリ通ることを確認した。

(ちなみに、Linux だけでなく Mac でも ping によるテストを行ったが、Linux と Mac では ping コマンドの仕様が違っていた。Linux では -M do オプションだったものが、Mac では -D オプションになっていた。)

2017年10月19日木曜日

Let's Encrypt がついに自動化される

StartSSL が使えなくなって以来代替として Let's Encrypt を使うしかなかったのだが、有効期間の短さのせいでこれまで深入りは避けどうしても SSL が必要なドメインだけで仕方なく使っていた。たった 2 つ、さくらインターネットで運用している自分のメインのホームページの独自ドメインと、もう一つは、QNAP の myqnapcloud.com のサブドメインである。

ところが、ここ一ヶ月の間で、QNAP もさくらインターネットも両方とも、Let's Encrypt に公式対応し、自動更新機能を含んだ形となった。お陰で、ただボタンをポチポチ押しておけば、証明書がセットされて SSL レディな状態になり、今まで証明書云々という情報を収集していたのが、ほとんど無駄になるくらい簡単になってしまった。

さくらインターネットの方では一つだけつっかかったところがあって、ドメインの管理はムームードメインのムームー DNS を使っており、blog は blogspot.com へ、www はさくらインターネットのサーバーの IP アドレスへと振り分ける形にしていた。このドメインにおいて Let's Encrypt の設定がエラーが出てしまった。

原因は、www を付けない状態での DNS 設定が存在しなかったせいである。さくらインターネットの Let's Encrypt では、www を付けないドメイン名も指定しようとするので、エラーになる。なので、ムームー DNS の方で、何も付けない空欄の A レコード(www と同様に IP に割り付ける)を追加して、しばらく時間が経過してから、さくら側で Let's Encrypt の登録と試すと今度は成功した。

カレンダー

カレンダーは Linux とは関係がなく Android で Google カレンダーを使っていたのみ(Linux ではブラウザ上で利用)。Mac に乗り換えたのでついでに macOS 標準のカレンダーアプリ(iCal)に、Google のカレンダーをセットしてみた。

基本的には Google アカウントをセットするだけだが、同期設定で少々調整した。このような iCal 向けの設定がわざわざ用意されているのは、iCal でも祝日や連絡帳の誕生日の表示機能があるので、Google 側の表示と二重に表示されないように考慮されているのだろう。自分の場合は基本的に祝日・誕生日などの表示は iCal 側に任せて、Google カレンダーの方は同期設定で off にした。


もちろん、iPhone と Mac の組み合わせなら、Google カレンダーを止めて、iCloud ベースのカレンダーにしてしまえる。自分の場合現状は MacBook と Android との組み合わせなので、Google カレンダーベースにしている。

FTP クライアント

macOS 用の FTP クライアントは他にもいくつかあるようだが、Linux でも共通して使えるので、FileZilla にした。

Linux から macOS への設定データの移行は、Linux 側からエクスポートした FileZilla.xml を Mac 側の FileZilla でインポートするだけ。

Thunderbird (Linux) から Mail (macOS) へのデータの移行

Thunderbird 同士であれば、Linux でも macOS でも(Windows でも)、基本的に Profiles ディレクトリ下にある XXX.default フォルダを移動すればいいので、データの移行に苦労することはない。

今回は、Linux から macOS の移行に伴って、メーラーも Thunderbird から macOS 標準の Mail アプリに乗り換えてみることにしたため、多少記録に値する点はあった。

まず、Linux から macOS には、Thunderbird の XXX.default を持ってくるだけでよい。macOS 側でわざわざ Thunderbird をインストールする必要はない。

次に、ここがネット上の情報では誰も触れていなかった点だが、Mail アプリで「ファイル > メールボックスを読み込む」によって XXX.default を読み込ませる時、Thunderbird 用のオプションが存在せず、「mboxフォーマットのファイル」を選ぶという点である。おそらく、Thuderbird 用のオプションがあったというのは古い情報なのだろう。

以上で問題なくデータの移行が完了した。

2017年10月18日水曜日

Samba

元の Linux マシンと MacBook の間でファイルを移動するために、Linux 側に Samba を導入した。Linux 黎明期から異 OS 間でのファイル共有で定番だった Samba だが、今でも代替が出てきておらず、第一線で使われているということを知って少し驚いた。

いくつか詰まった点としては、GUI で共有オプションなどを指定しても、何も機能せず、結局は /etc/samba/smb.conf を直接編集する必要があった。もしかしたらこれは権限の問題で、root 権限でログインしていたら、GUI でも直接操作できたのかもしれない。

また、Samba の設定でいくらパーミッションを設定しても、それが実際のファイルに付与されている権限を変更するわけではないので、あくまでも Samba で設定した権限の範囲内で、実際のファイルへそのファイルの権限に基いたアクセスが行われるという扱いのようである。

さらに、Samba を通じてアクセスするクライアント側で求められるユーザー認証は、Samba で独自に設定するユーザーとパスワードなのには注意する。Linux マシンにおけるユーザーアカウントとは関係がない。次のコマンドで設定する:

sudo smbpasswd -a <user name>

Inkscape

Inkscape (0.92.1) の macOS 版は Linux や Windows に比べて移植が遅れている感が否めない。XQuartz 版が嫌になったので、Homebrew 版を使うことにした。

まず、Homebrew 自体をインストールしなければならないが、OS のインストールなどでインターネット(WiMAX)の通信規制がかかっていた状況下で Homebrew をインストールしようとしたら、タイムアウトが発生してセットアップ処理が途中で失敗して駄目だった。規制が解除された状況下ではスムーズに Homebrew のインストール・セットアップが完了した。

そして、Homebrew が整ったので、あとは Inkscape の formula を実行してインストールすることができた。ちなみに Inkscape のインストール過程でコンパイル処理が発生するので、一定に時間を要する。この非力な初代 Macbook ではコンパイルに約 35 分、全体で 50 分程度かかった。

FileVault

初代 MacBook のこのマシンで、暗号化に約 10 時間かかった。

2017年10月15日日曜日

Night Shift

Sierra からだったと思うが、今は macOS も標準で Night Shift が使えるので、当然利用する。

設定 > ディスプレイ > Night Shift > スケジュール:日の入から日の出まで

Night Shift が自動で有効になっている時間帯に、一時的に Night Shift を切りたい場合は、「設定 > ディスプレイ > Night Shift > 手動:☑日の出までオンにする」のチェックを外せばよい。

ナチュラルスクロール

残念ながら(というか賢明でもあるのだが)、トラックパッドのジェスチャーと、マウスのホイールのスクロールの方向性をナチュラルスクロールにするか(リバーススクロールにするか)という設定は連動しており、別々に設定できない。

現状では未だ完全に Mac に移行できていないので、Linux と Mac の両股をかけている状態なのだが、Linux の方はマウスのホイールの方向を設定する余地がなく(トラックパッドのみ設定可)、Windows と同じ、リバーススクロール一択なので、そちらとの関係上、当面は(トラックパッドとの間の操作性の一貫性に反するものの敢えて)マウスのホイールに関してはリバースにしたかったのだが、Mac は Mac で仕様的に不可能であった。

Mousecape(左利き用マウスポインター)

Mac でマウスポインターを左利き用に表示するための定番は Mousecape(0.0.5)を使うことだが、以前の macOS で発生していなかった問題が、最近の OS では発生しているようである。Mac を再起動すると、自動で左利き用の .cape 設定に切り替ってくれないのである。

同様の問題は公式 github でも issue #45 として報告されており、ghost 氏のコメントの詳述が当てはまることが確認できた。すなわち、Mousecape をインストール後、OS デフォルトのマウスポインターを dump し、その dump した .cape を左利き設定で適用する。起動時に自動的に適用されるようにするために、(Mousecape の中から)Helper Tool をインストールする。が、そもそも .cape を適用しても、実は適用されておらず、Applied Cape: None のままで選択した .cape に緑のチェックマークが付いていない。.cape を適用する処理で、左利き用に反転する処理は行われるものの、何らカスタム .cape が選ばれた状態になっていないのである。そのため、再起動時にカスタム .cape を適用する処理が走らず、そのために左利き用に反転する処理も行われないので、このような問題が発生する。ghost 氏は、dump の使用は諦め、.cape を新規作成してこの問題を回避したと述べている。

ghost 氏のように新規作成するのはそれはそれで大変そうだったので、僕の場合、この MacBook を譲り受けた際、元々僕が頼まれて Mousecape の左利き設定なども行っていたという経緯があり、初期化前に .cape だけ旧いのをバックアップしてあった。それを持ってきて、Mousecape に .cape をインポートしたもの適用すると、上のような問題は起きず、Applied Cape: Cursor Dump という風に表示され緑のチェックマークも付く。再起動でも Helper Tool が適切に働く。

ただし、この Cursor Dump は旧い macOS での dump なので、サイズなどが違うせいなのか、微妙に色などが異なっていて、レインボーカーソルなどが白っぽい表示になってしまっている。これを解消しようとして、.cape の中身を最新の dump にコピー&ペーストして置換してみたりもしてみたが、そのようにすると再び Applied Cape: None の扱いとなる。

通常の矢印のポインターについては特に支障ないので、仕方ないので、旧い Cursor Dump で運用している。

※別の対処方法としては、Automator を使って、Mousecape を起動し、Cursor Dump を適用する操作自体を記録し、それをログイン時の起動アプリとして登録する方法もある。ただしこちらはこちらで、なぜか、Bluetooth マウスを接続していると、起動アプリが実行されなかったりしても、不安定なところがあった。

AquaSKK

Mac で SKK と言えば、AquaSKK (4.4.5)

OS 側の完璧な設定方法は次の通り:

設定 > キーボード > 入力ソース

入力ソースの設定

1. 英語は [@] ASCII を追加

2. 日本語は [ア] カタカナ、[あ] ひらかな、[英] 全角英数、[カナ] 半角カナ、[あ] 日本語(※1)を追加(※2)

3. U.S. を削除

4. [あ] 日本語 を削除

5. 以上で、SKK のみの入力モード間での切り替えとなる。

※1 [あ] 日本語 は macOS デフォルトの日本語変換システム(旧ことえり)

※2 AquaSKK 統合は選択しない

その他

  • メニューバーに入力メニューを表示:ON
  • caps lock ⇄ control の入替:「設定 > キーボード」の右下の「修飾キー」において設定
  • 入力ソースの切り替えショートカットキー:(shift+)command+space

2017年10月11日水曜日

Apple ID の 2 ファクタ認証の落し穴(というか明確なバグ)

Apple ID のアクティベーションにまつわる問題はようやくクリアされ、OS を High Sierra にアップデートし、色々と初期設定していた。その過程で、FileVault による暗号化処理を開始したのだが、いかんせん初代 MacBook のせいか、残り時間が「あと 1 日以上」と表示され、いつになったら終わるのかわからないような状況になっていた。

FileVault による暗号化処理の進行中でも、並行して Mac は使える。ちょうどそのタイミングで、High Sierra の追加アップデートが配信された。それでそちらもアップデートしたら、再起動を伴うアップデートだった。これが、FileVault で中途半端に暗号化処理がされていたことと競合し、OS のアップデートの処理が再起動した後に進まなくなり、仕方ないので再度 HDD 初期化、OS の再インストールすることを余儀なくされた。

ところが、iCloud の初期設定で Apple ID でログインしようとしたところ、2 ファクタ認証の、2 ステップ目、6 ケタの認証コードがスマートフォン(非 iOS デバイス)に届かないのである。音声通話で認証コードをリクエストしても同じ。

OS の初期化以前は、MacBook 自体が信頼できるデバイスとして、MacBook に認証コードが届いていた。初期化によって MacBook は一旦削除されたので、残るはスマートフォンの SMS か音声通話しかない。

ウェブから直接、Apple ID アカウントにログインしようとしても、やはり 2 ステップ目で進めなくなるのは同じである。アカウントのパスワードリセットをしようとしても、そのためにもまた 2 ファクタ認証となり埒が明かず、何度も繰り返していたら、今度は一時的なロック状態になり、サポートに相談したところ数時間待つようにと、言われた。しかし、これは短時間での連続ログインによるロックだから、どのみちそのロックが解除されても、やはり 2 ステップ目の問題は何も解消できていないのである。

連続ログインによるロックの時限解除を待って、ウェブから Apple ID アカウントのパスワードリセットを試みられるようになっていたので、とりあえずパスワードリセットの手続を開始した。

アカウントのリセットの場合、これは、セキュリティ上の仕様として、2、3 日時間をかけて処理が進むようにしてある。これはまあ、致し方がない。Apple から解除を予告するメールが送信されてくるのだが、そのメールに記載された電話番号の表記を見て、ふと閃いたのである。

リセットの手続において、電話番号を以前の認証の受け取れない携帯の電話番号ではなく、IP 電話の番号にしておいたのだが、その番号が国際番号と合わせて +81 50XXXXXXXX という風にメールに記載されてあった。

ところが、2 ファクタ認証の画面で認証コードを送りましたと表記される携帯の電話番号は +81 070XXXXXXXX となっていたのである。「ああ、これのせいか!」と。

つまり、Apple ID(管理サーバー)のバグ。国内の電話番号の先頭に 0 を付けても付けなくても、登録を受け付けるようになっているわけだが、にもかかわず、実際は 0 を付けない、国際電話番号としての表記でしか、適切に扱えないという仕様上のバグである。

おそらく、2 ファクタ認証を使っている多くの人が、iOS デバイスを所有し、僕のように、非 iOS デバイスの携帯電話番号(SMS / 音声通話)のみというユーザーは稀なケースであり、かつ、国内と国際電話で 0 を付ける付けないという日本の電話の仕様がアメリカの電話の仕様と異なっているという事情から、このようなバグに Apple の中の人は未だ気付いていないのだろう。

Apple ID アカウント復旧後、念のために IP 電話の登録は残しておいて、改めて SMS 認証用に携帯電話番号を 0 抜きで登録し直しておいたのは、言うまでもない。

2017年10月10日火曜日

この Apple ID は、App Store で使用されたことがありません

自分が買うつもりでスペックを見立てた MacBook Pro(13 インチ・タッチバー付)の購入計画を身内に取られた(?)ので、自分自身の Mac 購入計画は一旦流れた形になったが、その身内が元々使っていた MacBook(初代 2015 年モデル)をもらってひとまず使ってみることにした。メイン機として使う場合は、Android やゆくゆくは iOS アプリのプログラミングに使うつもりなので、処理能力的にはすぐに不満になってしかるべきスペックの iMac または MabBook Pro を購入する可能性はあるが、今はひとまず一通り使ってみて、様々な使い勝手を知り尽す目的でこの MacBook を使うことにした。

まあ、元来 Linux ユーザーである身からすれば、macOS というのはエキスパートユーザーであっても、非エンジニア(プログラマー)人種、せいぜいシステムアドミニストレーター系の人種(ジーニアスバーとかサポートの人たちもこれに含まれるだろう)にとっての進化の最先端にある OS であって、Windows との比較で圧倒的な価値を持つものの、Linux のような、ユーザー層とエンジニア層の重なる度合いが高い世界とはベクトルが異次元であり、比較にならない。Linux ユーザーにとって、自分で OS をインストールすることのようなシスアド業務は、まず最初のスタートラインに過ぎないわけである。

ちょいちょいとネットで情報を収集して、譲り受けた MacBook をおもむろにフォーマットして初期化し、OS の再インストールを行った。何一つ難しいことはなく、ほとんど勝手にインストールは終った。こういうのを怖がって、最初の一歩すら踏み出せない人って何なんだろう?──だが、非エンジニア人種という名の世間の一般ユーザーは、そういうものである。Apple 製品の主たるユーザー層に何を求めるというのだ?

OS の再インストールで、OS のバージョンは古い、El Capitan あたりに戻ってしまうので、App Store から最近出たばかりの High Sierra をダウンロードして、アップデートしようとした。

ここで問題が発生した。

Apple ID によるサインインができないのである。もちろん、パスワードを紛失したとかの、素人レベルのミスではない。「この Apple ID は、App Store で使用されたことがありません」というエラー表示が出て、サインインを拒まれるのである。

ネット情報によると、クレジットカード情報を登録すればいいとか、iTunes アプリでサインインするといいなどといった情報が引っ掛かったのだが、すべて試したものの、依然として事態は打開できない。

まず、iTunes アプリでも、iBook アプリでも、App Store アプリと同じで「この Apple ID は、iTunes で使用されたことがありません」というエラー表示が出て同じ状態に陥る。Windows に iTunes アプリをインストールしても同じである。そもそもクレジットカード情報はウェブの Apple ID アカウントで入力して登録済。しかし、敢えてエラー表示からアカウントのレビュー表示へと進んで、改めて登録内容を入力し直そうとするが、クレジットカード情報を更新する画面で更新内容を確定できず、内容の説明なしに赤い文字で www.apple.com/support/itunes/ww/ を参照せよというエラー表示がフォーム脇に表示されるのみ。

これはもう、こちらのやり方が間違っているという次元の話ではなくて(そういう低次元の問題であれば、ウェブの情報と自分で試行錯誤すればどうにかできる)、Apple ID アカウントに関する Apple 側の管轄する問題であると判断し、サポートに電話した。

全体で連続 2 時間ほど要したが、あちこちの部署をリレーされ、最終的に、iTunes 担当のサポートの方で、アカウントのロックを解除。詳細は教えてくれなかったが、何らかのロックがかかっていたようだ。自分は、iPhone を所有したことがなく、今回、MacBook Pro を購入するにあたって初めて Apple ID アカウントを作成したので、そのあたりも関係したいたのだろうか? このロック解除で、クレジットカードの更新画面で出ていた www.apple.com/support/itunes/ww/ のエラー表示は出なくなったものの、依然として確定できない。

そこで、改めて、iTunes の担当から戻された Mac のサポート担当者に、iTunes アプリでのサインインを試すよう指示され、成功。ようやく、ネットで言われていた話へとつながり、App Store アプリでも「使用されたことがありません」エラーは解消されたのだった。

つまり、ネットの情報だけでは解決できなかった理由は、iTunes のアカウントのロックの問題と、「使用されたことがありません」エラーは App Store ではなくて iTunes アプリでしかアクティベーションが不可能である問題の、2 種の問題が重なっていたということのようだ。

Apple という会社は iPod (iTunes) → iPhone (iOS) を中心に会社が回ってきた経緯があるから、iTunes や iOS の利用を前提とせず、いきなり Apple ID アカウントを作って Mac だけを使い始めるユーザーのケースについて十分に設計が考慮されていない体制になってしまっていても、まあ不思議でない。しかし、1ユーザーの立場としては、Mac にはずっと憧れを持ってきたので(自分にとっては、あくまでも、今でも、iPhone は Mac の付属物的な位置付けである)、いきなり身に染み付いたエンジニア的習性による行為から、今回のようなハマリ事態に直面するとは、皮肉だ。すっかり Mac は、iPhone の(アプリをプログラミングするための)付属物の立場に、なり下りきっていたということを具体的に自分で身をもって思い知らされた形になったのだから。

2017年9月23日土曜日

一石二鳥は諸悪の根源

飛行機の搭乗手続におけるオーバーブッキングのケースについての記事「なぜ全日空は定員オーバーで飛ぼうとしたのか?」で「一石二鳥は諸悪の根源」という設計工学の考えが紹介されていた。

設計工学の世界には「一石二鳥は諸悪の根源」と考える学派がある。一つの部品に複数の役目を負わせると、事故はそこから始まることが多いのだ。

……

ミスをなくすには、「一人二役」を分離することが望ましい。

これは設計工学特有の話としてではなくて、むしろ「設計工学でもそういう風に言われているんだ」と思った。

中学数学の1次方程式で、やり方は一応授業で習って理解できているのに、実際に問題を解く場面で計算ミスを多発してテストで失点する生徒というのは、移項(加減)と x の係数を 1 にする計算(乗除)を一緒くたにして暗算しようとするのが原因であるのが多い。こういう子供には、移項と x の係数を 1 にする計算は途中式を分けてそれぞれのステップできっちり書いてやるべきだと強調することになる。まさしく上の引用の通りだろう。

同じようなことは、プログラミングでの、メソッドの定義にも言えるだろう。一行のコードで魔法のように処理が済むコードを考えたくなるのは山々で、特に、Perl で正規表現などに懲るとそういう傾向が増進されるのだが、Java でシンプルなループを記述した方がメンテナンス性も良いコードになるものである。このあたりが、関数型とオブジェクト指向の違いだろう。関数型は一石多鳥を目指す指向と親和性が高く、オブジェクト指向は一人一役に分けていく指向と親和性が高い。

2017年9月20日水曜日

MacBook Pro(13 インチ/タッチバー付/メモリー 16GB)購入

結局、MacBook Pro は ASCII カードではなく、ドコモ口座の VISA プリペイドで購入した。ちょうどドコモ口座がキャンペーンでキャッシュバック率が 1% → 4% になっていたのが理由。ちなみに、ASCII カード(オリコ)はポイント率 1% である。

このことで、2 年目までの補填率が 100% → 70% となってしまう。しかし、20 万以上する MacBook Pro の場合、70% になっても、依然、保険基準額は 14 万であり、どの道、補償上限の 10 万は超えてしまっている。つまり、部分的損失ではなく完全に損失した場合の話ではあるが、ASCII カードで購入するメリットはないわけである。そんなわけで、タイミング良くドコモ口座のキャンペーンがあったので、+3% を迷わず選んだ。


余談だが、実のところ自分用に買うつもりでいたはずの MacBook Pro だが、諸般の事情から結局今回は自分用ではなく身内用に買うことになった。もちろん、ASCII カードの関係上、名義は自分名義ではある。なので、この記事で、MacBook Pro を買ったと言いながら、一方で Mac ユーザーとしての話題が今後も出ないとしても全く自然なので、そこは誤解なきよう。

その MacBook Pro のセットアップだけはやってあげたのだが、タッチバー付 13 インチ版の最小スペックの CPU(3.1GHz デュアルコア Intel Core i5(Turbo Boost 使用時最大 3.5GHz)、64MB eDRAM)だったのもあるのだろうか。それほど速い感じはしなかった。今、自分が使っている 2011 年 8 月に購入した HP の 17 インチノート(Pavilion dv7-6100)は Core i7 2630QM(2.0GHz クワッドコア(Turbo Boost 時 2.9GHz)L3: 6MB)だが、それと比べて、コンパイル作業などが速い感じはしなかった。まあ、デュアルとクワッドの違い、macOS と Linux の違いもあるのだろうけど、6 年も経ってる割には、そんなに違いがないなと。

まあやはり、CPU の高速化の限界もあるし、15 インチ MacBook Pro ではなく、そもそも 13 インチの MacBook Pro であるから、バッテリー関係でただ速くすればいいという話でもないので、頭打ちにはなってはいても不思議ではないとは元から思ってはいたのだが、7 年前にほぼ 10 万で買えたものと、最新のタッチバー付、待望の Kaby Lake の載ったピカピカの 20 万超の MacBook Pro、安っぽっちい Air ではなく、Pro がですよ。世間の非エンジニア側の特に文系の人々がこれでもかと絶賛しまくる新型の MacBook Pro が、実際買ってみたら、え、こんなの? と。ダサダサ Windows パソコンの 6 年前のモデルと大差なかった。これはちょっと意外でしたね。あ、いや、この HP のノートにデュアルブートで載っている Windows 10 は劇重なので、単に Linux が優秀過ぎるだけなのかもしれませんが。うん、そうに違いない。

2017年9月19日火曜日

Yahoo! JAPAN カード増枠

mastercard から JCB への国際ブランド変更のために作り直した Yahoo! JAPAN カード。元の枠は 50 万だったが、30 万での再スタートだった。ちょうど半年経って、18 日にいきなり YJ カードから増枠通知のメール。30 万→ 50 万へ。元の鞘に収まった。

ちなみに、元の mastercard の時は、20 万スタートで、半年経って即こちらから増枠希望を出して 50 万に上がっていた。

2017年8月25日金曜日

ASCII カード

そろそろ Macbook Pro でも購入しようかと考えていたところ、ASCII カードなるものの存在を知り、作ってみた。オリコ版(mastercard)とニコス版(VISA)があり、海外旅行傷害保険が自動附帯という点だけではあるが優れていたので、オリコにした。

Macbook Pro のようなノートパソコンの場合、外に持ち歩くことを想定すると、保険のようなものは考えておきたくなる。とはいえ、AppleCare+ はそれなりに高くつく。AppleCare+ が念頭にあって、ASCII カードの補償内容を考えた場合、結構いいかなと思った。

例えば、13 インチ/タッチバー付/メモリー 16GBの Macbook Pro だと 220800 円(税別)で AppleCare+ は 25800 円(税別)である。AppleCare+ によって、購入後 2 〜 3 年目に自己負担 11800 〜 33800円(税別)で修理が 2 回まで受けられるようになる。

一方、ASCII カードの保証では、購入後 3 年を過ぎてからも、永久に何回でも補償が受けられる。ただし、自己負担は 1 万円で 1 万円を超えた分が補償され、上限は 1 回 10 万円。また、通常の故障に対する補償はされない。あくまでも、盗難や事故によって破損したようなケースについて補償対象となるので、AppleCare+ とは全く趣旨が異っている。

しかし、外に持ち歩くノート PC で補償を付けたくなる理由は、まさしく通常の故障ではなく偶発的な事故を恐れてのことなので、ASCII カードの補償内容でいいと思う。AppleCare+ が購入後 3 年目までで上記のケースでは 25800 円(税別)であるのに対して、ASCII カードの場合は年会費 1950 円(税別)であるから、3 年間で比較しても 5850 円(税別)となる。ASCII カードがあれば、AppleCare+ を付けようかどうか悩む必要はないと考えたわけだ。

ところで、カードが送付されて規定に目を通してから初めて気付いたことが一つだけあって、ASCII カードで購入しなかった場合は補填率 70% のところ、ASCII カードで購入した場合は補填率 100% となるという部分だが、これが購入後 2 年までという制限があった。2 年を過ぎると、ASCII カードで購入しなかった場合と同じになるので、他のポイント率の高いカードで購入することを優先するか、2 年間の補填率 +30% 分を優先するかどうかは考えどころである(※ちなみにオリコのポイントは nanaco に交換するとして、ステージ優遇がない場合のポイントの還元率は 0.5% である。)。

ところで、カードの裏面のサインを記入する部分を見たら、こんな状態だった。mastercard の場合は幅広で短い場合があるが、こんな横長のは初めて見た。なのに、確認コード(CVC)がこんな中央に刻印されていた。

2017年8月22日火曜日

QNAP で仮想ホスト運用を断念

実家の QNAP NAS の貧弱な性能では、CGI が使い物にならず、Web サーバーは結局、さくらインターネットでマルチドメインを運用することを廃止できないという結論に達した。その上、StartSSL が使い物にならなくなってしまったため、Let's Encrypt に移行したのだが、その機会に、QNAP のポートの割り当ても、デフォルトに戻した。つまり、Web UI 用に、80 (HTTP) と 443 (HTTPS) を割り当て、仮想ホストに 8080 (HTTP) と 8081 (HTTPS) という形である。index.php も元のものにした。

XXX.myqnapcloud.com 用のセキュリティ証明書だけ、Let's Encrypt で用意し、Web UI に HTTPS でアクセスしても証明書エラーが出ないようにしておいた。

2017年8月3日木曜日

Firebase Remote Config

Firebase Remote Config は Resources をクラウド化したようなもので、クラウド上から Resources の定義値を更新するような感覚で利用できる。Resources の内容の更新のためだけに APK を都度アップデートする必要がなくなるので、かなり勝手が良くなる。

もちろん、Resources の値にアクセスする場合よりはいくつかの手続が必要だが、かなり簡素化されている。一定の手続というのは、1: デフォルト値として用意したアプリ内部のリソース(XML)ファイルを読み込む; 2: キャッシュをクラウドから取得して更新する、という 2 つの手続である。後者は、キャッシュの更新間隔を決めることも含む。

以上の理解には、Google 公式ガイドの Sample App Walkthrough とそのサンプルのソースそのものを見るのが無駄なく必要十分だろう。

具体的内容については、Google 公式ではないどこかの誰かのブログのサンプルコードの類から学ぼうとしない方がいいと思う。

2017年7月17日月曜日

Decadent Minimalist

Suica 用のカード入れが摩耗して駄目になってしまったため、以前から目星を付けていた Decadent Minimalist を購入。昨日(2017-07-16)到着した。

カードが 12 枚入るラージサイズ版で一番値段が高いチタン製のバージョン。ちなみに画像ではモザイクをかけていますが、カスタムで銘入りにしています。

専用のマネークリップも買おう思っていましたが、カードとカードの間に 3 つ折りにして入れることもできるらしいと知り、マネークリップは買いませんでした。紙幣が何かの拍子に抜け落ちないとも限りませんが、とりあえず何とかなりそうです。

2017年6月28日水曜日

Let's Encrypt

Web サーバーの SSL 対応のために、無料の証明書を StartSSL で取得していたが、以前から、Chrome などが StartSSL の証明書を信用しない扱いとなっていた。

仕方ないので、Let's Encrypt にようやく移行した。Let's Encrypt を敬遠していた理由は、有効期間が非常に短い(3 ヶ月である)ことだったが、もうこればかりは仕方がない。作業は極力簡素化されているので、一度やってしまえば、二度目以降は苦労することもないだろう。

さくらインターネットで運用している独自ドメインで利用したが、「さくらのレンタルサーバーでLet's Encryptを使う」という記事が参考になった。この記事は、クライアント側では Mac OS-X を使っているので、その点は Ubuntu とは異なるが、さくらのサーバー側の作業は必要最小限の情報がまとまっていてわかりやすい。要するに、「certonly --manual」がポイント

  • Ubuntu での注意点は、なぜか、certbot コマンドが使えなかったので、/etc/letsencrypt の中の letsencrypt コマンドを使う必要があった点。さらに apt-get でインストールすると、root 権限でインストールされているので、その点なども注意する必要があるが、そのあたりは Let's Encrypt 側の話というよりは、Ubuntu 側の話となるので割愛する。
  • また、Google で Let's Encrypt を検索した時に、letsencrypt.jp なる、非常に紛らわしいドメインの非公式ページが Google のトップに出てきて、最初、何の気なしにその情報を公式(の日本語訳)と思って読んでいたせいで、遠回りになった。公式(英語)を読んだ方がずっと明解だった。こういう偽ブランド的情報はある意味性質が悪い。

2017年6月25日日曜日

池上彰の英語力

イランの街で掲げられた“DOWN WITH THE U.S.A”を見て曰く『「打倒アメリカ」と書いてある』ってドヤ顔で池上さん……

アメリカが中東(シリア)なんかで空爆してるのを指して、「爆弾がアメリカと一緒に降ってくる」って言ってるだけ、絵に描いてあることそのまんま、中学レベルの英語でしょう。

誰が「打倒」なんて言ってるかというと、イランの人がそのポスターで言っていないセリフだから、他ならぬ、池上さん(の脳内の誰か)のセリフってことになる。

というか、ちょっと以前にも、池上さんの出身母体である NHK の通常のニュースで、アメリカのシリア攻撃に対してイランで反米抗議運動が広がってるというものを見たことがあるけど、英語では“Americans go home!”で、単に中東への派兵をやめて「家に帰れ」ということしか言ってないのに、NHK の字幕は、「アメリカに死を!」だった。NHK と NHK ブランドに肯定的な日本全国津々浦々の視聴者はこういうレベルで世界を認識したつもりになっている。


  • 池上彰は英語が堪能である。自らの海外取材に駆使するだけではなく、NHK時代には国際シンポジウムの司会も英語でこなした。(公式ファンクラブの解説より)
  • 大学入試で英語の配点が高い慶應大学の出身。

これが日本の英語の現状。

2017年6月5日月曜日

Firebase と Admob のリンク

Firebase アカウント(A)で独自の Admob アカウントを用意しないで、別の Admob アカウント(B)に Firebase プロジェクトをリンクしたい場合のポイント。

普通に Admob アカウント(B)で Firebase とリンクしようとすると、その Admob アカウント側の Firebase アカウント内に新規にプロジェクトが作成されて Admob とリンクしようとする。これを避けるには、Admob アカウント(B)側の Firebase アカウント内に、Admob とリンクしたい Firebase(A)のプロジェクトを共有しておく必要がある。これは、Firebase(A)で、Admob アカウント(B)をユーザーとして追加しておく必要がある。この時、権限はオーナー権限である必要があるようだ。編集権限だと、Admob アカウント(B)側の Firebase アカウント内に Firebase(A)のプロジェクトが共有された状態になることはなるのだが、依然、Admob からリンクできない。

オーナー権限で共有された状態であると、Admob からリンクする際に、(新規プロジェクトの作成ではなく)既存のプロジェクトとして選択できる状態で認識されるようになる。

2017年3月22日水曜日

Handler(mainLooper).post() を使うやり方と、runOnUithread() を使うやり方の違い

基本的に runOnUiThread() は Handler(mainLooper).post() へのラッパーとして用意されているが、メイン UI スレッドから実行する場合は挙動が異なる

メイン UI スレッドから実行した場合は、Handler(mainLooper).post() されずにスルーされて、そのまま Runnable の内容を実行する扱いとなる。なので、View の再描画など、強制的にタスクを発生させたいがために Handler(mainLooper).post() したい場合に、メイン UI から runOnUiThread() を使っても無意味なので、この場合は明示的に Handler(mainLooper).post() を記述して実行する必要がある。

cf. runOnUiThread vs Looper.getMainLooper().post in Android

2017年3月21日火曜日

PreferenceFragment

1 年以上ぶりくらいに本格的な Android プログラミングに回帰。そのせいか、固定観念から多少自由になったかもしれない。

例えば、PreferenceFragment。古い PreferenceActivity が obsolete になって、代わりに PreferenceFragment を使うように公式リファレンスに書かれている。それで、ネット上の情報をいくつか見ても、受け売りの解説ばかりなものだから、皆が自前の MyPreferenceActivity 的なるものを用意して、その中で PreferenceFragment を実装するような感じにしてる。

そこで今回、「そもそも、MainActivity で直接 PreferenceFragment を使っちゃいけない理由なんてあるのかい」と思って、やってみたら──できた!

今までの MyPreferenceActivity をわざわざ専用に用意して PreferenceFragment を使うやり方って、何だったのだろうか……。

受け売り情報撒き散らすのやめて欲しい。

いや、まあ、ブログなんだから、本来は各人の私的なメモという性格のものではあるんだろうけど。

2017年3月20日月曜日

2017年3月15日水曜日

カードのポートフォリオ

AMEX と Yahoo! JAPAN (MasterCard) をリストラしたので、ここいらでまたカードポートフォリオの現状を整理:

  • VIEW Suica (MasterCard) → Suica
  • 楽天 (JCB) → nanaco
  • ファミマT (JCB) → LINE Pay (JCB)
  • d GOLD (MasterCard) → iD
  • JACCS 横浜インビテーション (VISA)
  • MUFG VISA デビット (VISA) ※近日中に解約予定

依然、電子マネーに特化した陣容となっているのがわかりますね。

AMEX 解約

結局こうなりました……

YJ カード同様、手元にカードを用意すれば、電話の自動音声のみで解約手続を完結させることが可能でした。

Android の前方互換

2017-03-06 時点での Dashboards によると、Android のバージョン別シェアはこんな具合だった。

これならもはや、Jelly Bean (API16〜18) は切り捨てて問題ない。KitKat (API19) すら、戦略的な切り捨ての対象となる時期に入ったと言える。

Lollipop 以降を前提として開発すると、使える API 的に随分とコードをすっきりされられると思う。

2017年3月12日日曜日

プログラミング・パラダイム

結局、「オブジェクト指向プログラミング(OOP)」というのは、1) 手続指向は構造化で、2) データは構造体で、ということであり、この両者を、3) 構造化された手続(メソッド)を、構造体(オブジェクト)単位で整理することでまとめた、というだけの話であり、これ以上でもないし、これ以下でもないのではないかと思う。


手続自体は、あくまでも構造化プログラミング的な観点で整理を行なうべきで、これを生半可なオブジェクト指向的観点で整理すると、コードが無茶苦茶になって却って“百害あって一利なし”といっても言い過ぎにはならない気がする。少なくとも、自分の場合はそうである。

そうやって、構造化プログラミング的にすっきりと整えられた個々のコードが、集合して複数のコード群としてそのままそこいらにぶちまけられている時に、手続指向の限界が急にクローズアップされてくる。

この時に整理整頓の“容れ物”として俄かに脚光を浴びることになるのが、構造体(オブジェクト)である。手続のためのコードをそのまま“裸”でそこいらにぶちまけては置かないようにしよう、必ず、構造体に入れられた(カプセル化)状態で置いておくことにしようね、というのが僕流のオブジェクト指向像である。


上のことをちゃんと自覚していないで、「オブジェクト指向スゲー」で何でもかんでもオブジェクト指向のノリを持ち込もうとすると、むしろコードの見通しが悪くなって、あっちへ飛んだり、こっちへ飛んだりと、ダイクストラ先生が「goto は使わないようにしよう」といった時代の事情に逆戻りして、あっちのメソッドこっちのメソッドを飛び回るような、いわば「goto なきスパゲッティ化プログラミング」に陥ってしまう。

新しいコードをスクラッチで組んでいく時、ここは手続指向で素直に、一つ一つの処理を継ぎ足して行ってプログラミングするのが、やはり王道なのではないかと思う。そしてそのコードが伸びるにつれ、(2回以上)多用される同様の処理は、サブルーチンとして分離する。そのことで、「コードをコピー&ペーストして使い回すことを避ける」というのが、構造化プログラミングの単純かつ肝となる原点だと思う。ある処理に関するコードが記述される場所を一元化することで、後に変更の必要が生じた時に、あちこちを修正して回るというようなことは避けないと、例えば、一部を修正し、一部は修正し漏らしていたりした場合に、バグを生む。

まずは、メインルーチンという一本道のコードに立ち戻って、そこから構造化的にサブルーチンを分離するという作業に立ち返るのが重要である。構造化の後、構造体の容れ物に構造化された手続ルーチンを収納するところまで終ったとする。次に、類似の別のクラスを作成する場面になり、既に完成されたクラスを意識して内部の一部の処理をいじって済ませようとするのだが、不思議なことに大概が上手くいかないのである。仕方がないので、オブジェクトというカプセル化されたシャーシ(筐体)をひっぺがして、手続指向的に一本道的な処理から一つ一つを確認して組み直していくと、面倒な作業のようでいて、不思議とスーッと進められていく。一つ一つ新しい処理を継ぎ足していくだけなのだから、「どこに問題があるのだろうか?」と悩んで、四苦八苦する苦労がないのである。

つまり、オブジェクト指向という、カプセル化作業は、あくまでも、内部処理が完成してから行なうべきであって、内部処理のコーディング作業が終ってない段階から、カプセル化の部分を並行して、混ぜて、作業を行ってはいけないのである。


この手続指向部分で作業を行なう段階と、オブジェクト指向で作業を行なう段階との間には、厳然たる断絶があって、互いの領分と先後の序列はキッチリと守られるべきであると思うのだ。例えば、同じ「食べ物」に関する産業でも、農業の分野と、外食産業の分野で、全く人材人種が別個であるというような、そのくらいの世界の違いが。農家の人に、「このレンコンは、洗ってお客様に出すから、最初から泥が付かない状態で育てておいて!」などと要求する料理長がいたら、レンコンが育つのだろうか? と。農家の人は作物を見てるし、料理人はお客さんを見ている。それぞれの立場によって、最適な視点というものが違う。世界に単一の視点(パラダイム)を押し付けようという発想こそが邪悪な根性なのだ。

2017年2月19日日曜日

オブジェクト指向プログラミングと構造化プログラミング

オブジェクト指向プログラミング(OOP)と構造化プログラミング(手続指向)を対立する概念だと思っていたが、どうやら間違っていたようだ。

詳細は別の機会でもあれば書くかもしれないが、両者は共存可能、というか共存させるのが適切だと思った。

この結論に達することで、メソッド定義の private と public、static と dynamic の使い分けもはっきり線引きできるようになったと思う。

  • 構造化プログラミングは static で、そのうちのサブルーチン部分は private、メインルーチンは public。
  • オブジェクト指向プログラミングは dynamic で、オブジェクトの操作に関するインターフェイスとしてのメソッドは public。

大ざっぱな分け方としてはそんな感じ。

2017年2月16日木曜日

期間限定dポイントの裏技

年末年始のキャンペーン(【dケータイ払いプラス】冬のスーパァ~チャンス!)で獲得したボーナスポイントの期限がそろそろ迫ってきたので、適当に対処しておきました。

合計ポイント数は変わっていませんが、10 回の処理の結果、内訳の期間・用途限定ポイントが 500 ポイント分減って(通常ポイントと入れ替わって)いるのがわかります。


2017-03-12 追記:3月初めに、ローソンのシステムが修正され、上記裏技が塞がれたようです。(期間限定ポイントはすべて変換済ではあったものの)たった一回しか活躍の機会がなかったとは、とほほ……

2017年1月19日木曜日

YJ カード解約

踏ん切りが付かずにずるずると先延ばしにしてきたが、Yahoo JAPAN! カード(MasterCard)をついに解約。

電話の自動応答だけで解約手続が全て完結してしまう。暗証番号すら不要で、必要な情報はカード番号と生年月日のみ。

ちなみに、ここだけの情報だが、YJ カードのナビダイヤルの方へ電話をかけなくても、普通の電話番号があり、カケホーダイ契約の携帯からそちらにかけて済ませることができた。

  • ワイジェイカード株式会社 お客様相談室 092-451-5971(平日9:30~17:30)