applied for reviewing #2

Chrome、Opera、Firefox のそれぞれの公式エクステンション配布サイトへ申請した。

申請した後のレスポンスが各々違うのが興味深い。

Chrome の Web Store は人の手によるレビューはないに等しいようだ。この辺はいかにも google らしい。Opera は人手なんか足りてないだろうにレビューをしてくれる。提出して数時間で返答が来た(extension の紹介のための description が簡潔すぎるからもっと詳しく書けや、というものだったのでコードレビューにはまだ至ってないようだ)のには驚いた。レビュー開始されるまで何ヶ月かかるか? と冗談でなく思っていた。

Firefox は最近になって、レビュー方法が 2 種類になったらしい。full review と preliminary review だ。後者の方はその名の通り事前審査ということで、完全な審査が行われる前でもとりあえず公開される形式。ただし AMO で検索しても出てこない。あくまで少数向けに公開してバグ取りしましょ…という段階を経るためのもののようだ。とりあえず preliminary review で申請した。

いずれにしても正式に公開されるのはしばらくかかりそうだ。

applied for reviewing

Chrome、Opera、Firefox の各エクステンションの公式配布サイトへ、ぼちぼち申請している。Chrome、Opera は申請は特に問題なく進んだ(申請が終わっただけ。公開はまだされてないと思う)。

その調子で、Firefox の AMO にも申請しようと思って Firefox を立ち上げて、AMO へ行って、xpi をアップロードしろというから青いボタンを押したわけですよ。だいたいこのパターンだとアップロードするファイルを指定するためのダイアログが出るんだろうなーなどと予測しつつ。

で、どうなったか。

一向に何も起こらない。ボタンを押しても何も変化が起こらないのである。Opera だとこういうことはわりかし起こりうるので、それを見越して Firefox を立ち上げたのだが……。

そういうわけで、まさかと思いつつ、Chrome を立ち上げてアップロードボタンを押してみたら何事もなくアップロードされたのであった。単にうちの環境の問題ならいいんだけど、もし普遍的な不具合であるならあまりと言えばあまりにみっともないのではやく直したほうがいいと思います。

ちなみにアップロード直後の機械的なスキャンで、やたら多くの警告が出たのでひとまずそれを直さなくてはならない(github 上の SDK を使ってるのが原因だと思う)。

とりあえず今んとこそんな感じ。

updating manifest #2

以下の変更を施した:

  • バックグラウンドにおいて、chrome.self がなくなっている。これは chrome.extension のエイリアスだった。したがって単に chrome.extension に書き換える
  • extension 内に納められた html ファイルを通常のページから参照する際、どのファイルが参照可能であるかを manifest.json の web_accessible_resources で指定するようになったので、wasavi_frame.html を指定
  • manifest.json の background_page がちょっと複雑な文法と共に background へ変更になったので、追従
  • extension 内に納められた html ファイルにインラインで javascript を記述しても、それは絶対に実行されなくなった。この制限は緩和できない。script 要素を src 属性付きで記述するしかない。
  • eval() が禁止された。しかし、content security policy の仕様に従うなら、manifest.json で content_security_policy に script-src ‘unsafe-eval’ とかなんとか書けば使用できると思うのだが、そういう仕様なのかバグなのか、書いても使用できない。

    wasavi の中では 1 箇所だけ eval() ……というか new Function() を使っている。textarea にフォーカスがあるときにキー入力がされたとして、それが wasavi 起動のためのショートカットかどうかを判定する部分だ。

    ショートカット自身はバックグラウンドが保持し、必要に応じて通常のページ上のエージェントに送られるのだが、送られるのはオプションページで指定するような “<c-enter>” とかいった文字列ではなく、それを javascript の式に変換した “return e.keyCode==13;” といった文字列で、エージェント側でこれを元に new Function() し、ショートカットの判定に使う。これはまさに w3c のドキュメントがいうところの performance optimizations に該当する。w3c のドキュメントでは eval が使えなかったらパフォーマンスで劣るけどもっと安全な方法にフォールバックすればいいんじゃない? なんて虫のいいことが書いてある。

    しかたがないので new Function() せずに済ます方法に書き換えた。

updating manifest

Chromeの場合、extension の素性を示すデータとして manifest.json を必要とする。

この manifest、Chrome のバージョンアップにしたがって緩やかにフォーマットが変化している、らしいということを最近知った。Chrome 18 からは manifest_version: 2 が推奨だという。2 未満を指定した extension も(今のところ)そのまま動作するのだが、Web Store に登録するには 2 じゃないとだめなんだそうな。

manifest_version が 1 か 2 かの違いは文書化されている。小さな違いから大きな違いまでさまざまなのだが、文書に含まれるスクリプトの扱いなんかは content security policy に従わなければならないのがもっとも大きな違いだと思う。

ということで、manifest_version:2 にしたらさっぱり動かなくなったのでいろいろ弄っている。

0.4.169 released

http://appsweets.net/wasavi/

  • textarea / input 要素がフォーカスを得たときに自動的に wasavi が起動するオプションを追加した

オプションの変更は、各ブラウザのエクステンション管理ページ的なものから辿れるようにしてあるが、実は既に起動している適当な wasavi で
:options
と打っても設定ページを開くことができる。

quick activating #2

dropbox から返答があり、無事承認された。

 * * *

で。

自動的に起動した wasavi が、これまた自動的に終了するには 2 つの方法がある。まず、ユーザが明示的に wasavi から他の要素にフォーカスを移した場合。これはフォーカス可能な要素に限らず、単に body をクリックした場合も含まれる。いずれにしても、wasavi がフォーカスを失う時点での編集内容が textarea に反映され、wasavi は終了する。フォーカスはユーザが指定した要素にある。

次に、wasavi の起動中にコマンドモードで tab を押下した場合。この場合も wasavi のその時点の編集内容が textarea に反映され、wasavi は終了するのだが、前者との違いは、wasavi が拡張する対象となる textarea の次の tabindex を持つ要素にフォーカスされることだ。

つまり両者の違いは、wasavi の終了後にどの要素にフォーカスが移るかだ。前者は移行先要素をユーザが明示し、後者は暗黙的なので explicit deactivation と implicit deactivation と区別することができると思う。

で。

問題は、後者の implicit deactivation において、ある要素の、sequential focus navigation に沿った上での次の要素を求める手段が、標準的な API では提供されていないということだ。HTMLElement#nextFocusingElement みたいなのがあれば一発なんだけど。

sequential focus navigation というのは、PC 上のブラウザにおいては、tab キーを押すことで順繰りに、適当な要素にフォーカスが移っていく操作のことだ。適当な要素というのは、既定では

  • href 属性を備えた a 要素
  • href 属性を備えた link 要素
  • disabled ではない button 要素
  • disalbed ではなく、かつ type が hidden ではない input 要素
  • disabled ではない select 要素
  • disabled ではない textarea 要素
  • disalbed ではない command 要素
  • draggable 属性を備えた要素。ただし、ユーザーエージェントがポインティングデバイスを使うことなくドラッグ開始することを許可している場合
  • エディティング・ホスト
  • ブラウジング・コンテキスト・コンテナ

これに加えて、tabindex でインデックスが 0 と明示してある要素、および 0 以上の値が明示してある要素が sequential focus navigation の対象となる。前者は前後関係は文書順に従って自動的に決められるが、後者は順番は指定された tabindex に従う。

フォーカスを受け取れる要素は、以下の順になる:

  1. tabindex が 0 より大きい要素群(同一の tabindex では文書順)
  2. tabindex が無効な(指定されていないか、パース結果がエラーとなる)要素群
  3. tabindex が 0 以下と明示してある要素群
  4. このうち sequential focus navigation は 1. と 2. の要素群が対象になる。

    結局のところ、それらの要素群を抜き出し、wasavi の拡張対象となる要素を探し出し、その次の要素にフォーカスを移せばいい。

    ……すごく面倒くさいです! ブラウザ自身が持っている情報なのに、わざわざ javascript で算出するのはとても無駄です。

quick activating

コンシューマキー/シークレットを blowfish で暗号化して保存するようにしたバージョンで dropbox へ再申請した。

0.4.163 を某所でアナウンスしたところ

Ctrl+enter無しでデフォでオンになると嬉しい

というコメントがあった。

これはつまり、textarea 要素にフォーカスを移した時点で自動的に wasavi が起動してほしいということだと思う。確かにそのほうが、いちいち ctrl+enter するよりも使いやすい場面はたくさんあるだろう。textarea そのものが vi のインターフェースを備えたものとして扱えた方が、vi に慣れきった層にとってはこの上ないメリットになると考えられる。よしやろう是非やろう。

しかし隠れたデメリットをあげてみると、意外に少なくない:

  1. 実際の web ページ上の textarea 要素は、実際に送信されるフォームの部品である。一方、wasavi の実体は textarea の上にかぶせた完全に別の要素である。wasavi が起動してテキストを編集したとしても、それを :write するまでは textarea の値は更新されない。シームレスに起動したとしても、あくまでも別の要素の別の内容を編集していることには変わらない。もしシームレスに wasavi を起動させると、適当にテキストを編集 -> おもむろに送信ボタンをクリック -> 内容が送信されてねぇ! という事故が非常に高い確率で起こりうる。
  2. web ブラウザネイティブのフォーム部品は、tab キーを押すことでフォーカスを順繰りに遷移させることができる。wasavi が自動的に起動する際、すべてのキー入力は wasavi が処理する。マップされていないキー入力は何も起こらないとしても、wasavi が消費する。この動作はフォーカスの遷移とかち合うわけだが、どうするか?

1. 自動起動させる設定にした場合、wasavi 上で編集するごとに即 textarea 要素を更新する。あるいは wasavi がフォーカスを失ったら即 textarea 要素を更新する。いずれにしても :write は意味を持たなくなる。
2. 自動起動させる設定にした場合、wasavi のコマンドモードでの tab キーは予約される。標準のマップも、リマップもできなくなる。tab キーを押すと wasavi は終了し、対象の textarea 要素の次のフォーム部品へフォーカスが移動する。

こんな感じで解決できるかな?

ln -s

何かアプリケーションを作っているときは、たいていブラウザとエディタとターミナルを行ったり来たりしている。もっともターミナルと言っても素のコマンドプロンプトが使いやすいとは言えない(ckw とか nyaos とか、あるいは PowerShell を極めればそうではないのかもしれない)ので実際は cygwin なのだが。

で、ほとんどの場合 cygwin で間に合うのだけど、唯一シンボリックリンクの作成だけが管理者権限で実行したコマンドプロンプトじゃないと行えない。現在の cygwin では NTFS ネイティブのシンボリックリンクにある程度は対応している。ls もリンクを追跡する。ただし「ネイティブなシンボリックリンクの」作成はできない。ln -s はあるが、それが作るシンボリックリンクは cygwin でしか認識されない独自形式なのだ。

なぜこうなっているのかと言えば、シンボリックリンクの作成はどういうわけか管理者権限が必要だからだ。そのため cygwin 側としては「作成もできるようにしたいけど管理者権限が不要になるまでペンディング」という状態らしい(とメーリングリストか何かで見た記憶があるのだが場所を失念した)。

この制限が早く取り除かれればいいなあと思う今日この頃。

the secret only between you and me

dropbox の API を使用するアプリケーションには Production status というものがある。最初にアプリケーションを登録した段階では development で、アプリケーションを登録したアカウントしか使用できない。その後 dropbox へ申請することで production に移行し、誰でも使えるようになる。

ということで申請したら、却下された。

理由は OAuth のコンシューマキーとコンシューマシークレットを plaintext で保存してんじゃねーよ! せめて難読化しろやボケが! というものであった。とてももっともな話である。

過去の記事で考察したように、ブラウザのエクステンション(javascript なのでソースを見るのは容易い)にどうやって OAuth のコンシューマキー等を含めるかは難しい。

エクステンション内ではなく、適当なサーバを用意し、その中で OAuth を用いた API の使用認可を得るようにすればコンシューマキーの置き場所について考える必要はない、が、適当なサーバが提供する REST api を真に wasavi だけが使えるようにするための認可が更に必要になる。いずれにしろエクステンションの中に何らかの鍵を含めなければならず、結局同じことだ。ならば中継サーバを使う必要性はあまりない。

ということでエクステンションに鍵を難読化した上で収めるようにしなければならないのだが、難読化や暗号化したところでデバッガを立ち上げて復号した直後にブレークポイントを張るだけで真の内容が見られるのだからあんまり意味ないよなーと思っていた。思っていたが、dropbox 側で難読化しろと言うのだから、そういう方向にしようと思う。

とりあえず難読化というか、暗号化しよう。blowfish あたりでいいだろう。

Javascript Blowfish Library
https://github.com/takezoh/blowfish.js

コンシューマキーとコンシューマシークレットを収めた json ファイルを blowfish で暗号化し、base64 してそれをエクステンション内に収める。バックグラウンドの起動時にそれを復号する。

building a xpi #2

最新のソースをビルドしてみたのだが、Firefox で動かない。そもそもバックグラウンド部に当たる main.js が実行されていないか、あるいは途中でエラーになってるようだ。しかしエラーコンソールには何も出ていない。

動かない原因を探るのにも、Firefox + Add-on SDK では一苦労だ。まず Firebug でデバッグできない。できることはまずそうな箇所に console.log() をちりばめるくらいである。

そんなわけで原因は require() しているところのようだ、と分かりかけてきたのだけど…… cfx run で実行してみる分には普通に動くのだ。しかし xpi をビルドしてそれを Firefox にインストールしてみると動かない。先の記事の通り、必要なライブラリの有無の問題? と xpi の中を覗いてみても問題なさげ。

そういうわけでいろいろ試行錯誤してみたところ、意味が分からないことに console.log() を付加したり外したりするごとに main.js の最後まで通常通り実行されたり、途中で止まったり再現性のあまりない動作をすることに気が付いた。

うー、これは javascript のレベルでのバグじゃなくて Firefox のバイナリ自身のバグじゃないのかしら。ちなみにやはり先の記事の通り、main.js は minify してある。もしかしてこれが……? と、試しに minify せずに xpi をビルドしてみると、これが普通に動くのだ。えーそういうことなのか。

しかし minify しないと、xpi のサイズが 300KB 超になってしまう。Add-on SDK による xpi は SDK のコードも含むため、ただでさえサイズ大きめ(Chrome と Opera のエクステンションのサイズが 100KB 程度なのに対して、xpi は 200KB くらいになる)なのに、minify をしないとさらに増えてしまうわけだ。もっとも 300KB というサイズ自体が、21 世紀の今現在においては全然大したことのない大きさではあると思うが、Chrome/Opera/Firefox のそれぞれのエクステンションを並べたときに Firefox の xpi だけ異常に巨大なのはやはり不自然だ。

しかし minify すると動かないのだから背に腹は変えられない。300KB のままで公開することにした。

調べてみるとそもそも SDK 自体が jetpack と呼ばれていたものを一旦キャンセルした後作り直したものだったり、api の仕様がプロセス分離モデルを前提としていたのにプロセス分離モデル自体がキャンセルされたので無駄に複雑なものになってしまったり、デバッガが使えなかったり、IE の唯一のカウンターパートという立ち位置だったころは Firefox って超クールでナウいブラウザなイメージだったのだけど、最近はなんだか迷走続きでかなりイケてないなーと思いました。Firefox がんばれ超がんばれ。