株式会社クリアコード > ククログ

ククログ


Vimでgettext(Sphinx)の翻訳対象ファイルとPOファイルを紐付けて簡単に開けるようにする方法

横山です。この記事では、gettext(GNU gettext)を使って翻訳対象ファイルと翻訳ファイル(POファイル)をVimで編集するときの便利設定を紹介します。

gettextを使ったことがない方は、ククログの過去記事を読んでみると雰囲気がわかるかもしれません。

gettextによる翻訳は、まず翻訳対象のファイルからメッセージを抽出し、それぞれのメッセージに対応する翻訳をPOファイルに記述するという流れで行われます。翻訳対象のファイルとPOファイルの間を行き来することになるので、その手間を減らすのが今回の目標です。

バッファで開いておく、NERDTreeなどでブックマークしておくといった方法もあるのですが、POファイルの数が多いと探す時間がばかにならないので、翻訳対象ファイルに対応するPOファイルを自動で検出できると効率が上がります。*1

ここでは、vim-altrというプラグインを使ってみます。

vim-altrは、設定されたルールに従って、編集中のファイルに関連する別のファイルを開いてくれるプラグインです。 以下のように任意のキーバインドを設定して使います。

nmap <Leader>a  <Plug>(altr-forward)

デフォルトでもルールが用意されているので、各言語の一般的なファイル構成であればこれだけでいい感じに動作してくれるようです。 が、gettextの対象ファイルの配置はプロジェクトによって異なるため、これだけだと動作しないので、vimrcに設定を追加していきます。

ここではGroongaプロジェクトを例に説明します。GroongaではSphinxと一緒にgettextを使用していて、ドキュメント構成は以下のようになっています。

  • 翻訳対象ファイル(抜粋)
    • doc/source/news.rst(毎月更新)
    • doc/source/news/5.x.rst(ほとんど更新しない)
    • doc/source/news/6.x.rst(ほとんど更新しない)
    • doc/source/install.rst(ほとんど更新しない)
    • doc/source/install/debian.rst(たまに更新)
    • doc/source/install/centos.rst(たまに更新)
  • POファイル(抜粋)
    • doc/locale/ja/LC_MESSAGES/news.rst
      • news.rstとnews/5.x.rstとnews/6.x.rstが対象
    • doc/locale/ja/LC_MESSAGES/install.rst
      • install.rstとinstall/debian.rstとinstall/centos.rstが対象

上記の例の中では、更新頻度的に一番頻繁に行き来するのはdoc/source/news.rstとdoc/locale/ja/LC_MESSAGES/news.rstの間です。よって、まずはこの2ファイル用の設定を追加してみます。

1対1の関係のファイル間の移動

.rst(reStructuredText形式)決め打ちでよいのであれば、以下の1行をvimrcなどに追加するだけです。

call altr#define('doc/source/%.rst', 'doc/locale/ja/LC_MESSAGES/%.po')

これで、doc/source/news.rstとdoc/locale/ja/LC_MESSAGES/news.rstの間を設定したキーバインド(<Leader>aなど)で行き来することができるようになります。

.rst以外にも対応させておきたい場合、以下のように設定します。

call altr#define('doc/source/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')

(2018/5/10追記: 初稿では2行目として call altr#define('doc/locale/ja/LC_MESSAGES/%.po', 'doc/source/%.*') を記載していたのですが、これがなくてもaltr-forwardだけで行き来できました。)

`(altr-back)`に対するキーバインドを設定しておけば上の1行だけで行き来できる(altr-forwordでsourceから.po、altr-backで.poからsource)のですが、2行目を追加しておけば`(altr-forward)`だけで行き来できます。好みに応じて設定してください。

多対1の関係のファイル間の移動

頻度は多くありませんが、doc/source/install/debian.rstとdoc/locale/ja/LC_MESSAGES/install.rstの間や、doc/source/install/centos.rstとdoc/locale/ja/LC_MESSAGES/install.rstの間もたまに行き来します。これらは、複数の翻訳対象ファイルに1つのPOファイルが対応しています。このような場合、POファイルから翻訳対象ファイルを検出することは難しいので、翻訳対象ファイルからPOファイルへの一方通行の設定を追加しておくのがおすすめです。具体的には以下のような設定を追加します。

call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')

この設定を追加することで、doc/source/install/debian.rstやdoc/source/install/centos.rstからdoc/locale/ja/LC_MESSAGES/install.rstを簡単に開くことができるようになります。 この場合、翻訳対象ファイルに戻るときは、vim-altrではなくC-^(直前に開いていたバッファを開く)などを使うことになります。

細かいところですが、doc/source/%/%.*doc/source/%/*.*などとしてしまうと、doc/source/install/debian.rstとdoc/source/install/centos.rstがお互いに行き来する対象になってしまうので注意してください。

後から定義したルールが優先されるようなので、1対1と多対1の設定を両方追加する場合、以下のようにしておくと1対1のルールが優先されます(doc/locale/ja/LC_MESSAGES/news.poからaltr-forwardするときに、doc/source/news/ではなくdoc/source/news.rstが開かれるようになる)。

call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')
call altr#define('doc/source/%.*', 'doc/locale/ja/LC_MESSAGES/%.po')

1対1の関係のファイル間の移動の設定が不要であれば、以下のように.poからaltr-forwardするときは明示的にディレクトリを開くようにしておくのも一案だと思います。

call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po', 'doc/source/%/')

または

call altr#define('doc/source/%/%.*', 'doc/locale/ja/LC_MESSAGES/%.po', 'doc/source/')

まとめ

Vimでgettextの翻訳対象ファイルとPOファイルを紐付けて簡単に開けるようにする方法を紹介しました。 gettext以外にも応用できる方法だと思うので、ぜひ活用してみてください。

*1 POファイル自体はVimではなくPoeditなどで編集することが多いと思いますが、Poeditで編集するときでも、一旦Vimで開いてから

:! poedit % &
などでPoeditで開くようにすると、ファイルを探す手間が省けて効率が上がります。

タグ: Vim
2018-05-09

Debianパッケージのメンテナンスをsalsa.debian.orgに移行後にアップデートするには

はじめに

以前、Debianパッケージのメンテナンスをsalsa.debian.orgに移行するにはというタイトルで、パッケージのメンテナンスをsalsa.debian.orgに移行するのにともない、git-buildpackage(以降gbpと記載)のやりかたに合わせつつリリースするところまでの内容を記事にまとめました。

今回は、アップストリームで新しいバージョンがリリースされたときに、Debianパッケージをgbpを使って更新するときのやりかたを紹介します。

前提条件

gbpを使って作業する際、環境が違っているとそのままではうまくいかないことがあります。 そのため、本記事ではDebianパッケージのメンテナンスをsalsa.debian.orgに移行するにはで紹介した手順で環境をセットアップ済みであることを前提とします。

  • 前回記事で紹介した~/.gbp.confを設定している
  • ブランチはmasterではなくdebian/unstableにしている
  • ビルド方法にはpbuilder+tmpfsを利用する構成になっている

Groonga 8.0.1 から Groonga 8.0.2 にDebianパッケージを更新するのにどのようにしたかを説明します。

リポジトリをcloneする

作業用のリポジトリをcloneします。この操作にはsalsa.d.oにアカウントが必要です。https経由(https://salsa.debian.org/debian/groonga.git )ならsalsa.d.oにアカウントがなくても大丈夫です。

% git clone git@salsa.debian.org:debian/groonga.git

アップストリームのソースをインポートする

Groongaの場合、 debian/watch があるので以下のコマンドを実行することで、ソースをインポートすることができました。

% cd groonga
% gbp import-orig --uscan --debian-branch=debian/unstable
gbp:info: Launching uscan...
uscan: Newest version of groonga on remote site is 8.0.2, local version is 8.0.1
uscan:    => Newer package available from
      https://packages.groonga.org/source/groonga/groonga-8.0.2.tar.gz
gpgv: 2018年04月27日 17時47分26秒 JSTに施された署名
gpgv:                DSA鍵C97E4649A2051D0CEA1A73F972A7496B45499429を使用
gpgv: "groonga Key (groonga Official Signing Key) <packages@groonga.org>"からの正しい署名
gbp:info: Using uscan downloaded tarball ../groonga_8.0.2.orig.tar.gz
What is the upstream version? [8.0.2] 
gbp:info: Importing '../groonga_8.0.2.orig.gbp.tar.gz' to branch 'upstream' (filtering out ['*egg.info', '.bzr', '.hg', '.hgtags', '.svn', 'CVS', '*/debian/*', 'debian/*'])...
gbp:info: Source package is groonga
gbp:info: Upstream version is 8.0.2
gbp:info: Replacing upstream source on 'debian/unstable'
gbp:info: Successfully imported version 8.0.2 of ../groonga_8.0.2.orig.gbp.tar.gz

上記のようにすることで、 upstream ブランチと pristine-tar ブランチが更新されます。

% git checkout pristine-tar
Switched to branch 'pristine-tar'
Your branch is ahead of 'origin/pristine-tar' by 1 commit.
  (use "git push" to publish your local commits)
% git push
Counting objects: 4, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 399.92 KiB | 13.79 MiB/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote:
remote: To create a merge request for pristine-tar, visit:
remote:   https://salsa.debian.org/debian/groonga/merge_requests/new?merge_request%5Bsource_branch%5D=pristine-tar
remote:
To salsa.debian.org:debian/groonga.git
   f46d803..95ccd57  pristine-tar -> pristine-tar
% git checkout upstream
Switched to branch 'upstream'
Your branch is ahead of 'origin/upstream' by 1 commit.
  (use "git push" to publish your local commits)
% git push
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for upstream, visit:
remote:   https://salsa.debian.org/debian/groonga/merge_requests/new?merge_request%5Bsource_branch%5D=upstream
remote:
To salsa.debian.org:debian/groonga.git
   68022cf..8f10dc8  upstream -> upstream

更新されたブランチをそれぞれpushしておきます。

debian/changelogを更新する

アップストリームの更新であることを示す変更点を debian/changelog に記載します。

groonga (8.0.2-1) unstable; urgency=medium

  * New upstream version 8.0.2.

 -- Kentaro Hayashi <hayashi@clear-code.com>  Wed, 02 May 2018 10:25:09 +0900                                                              

パッケージをビルド、テストする

ここまでできたら、きちんとパッケージとしての体裁が整っているか、ビルドします。

% gbp buildpackage --git-ignore-new

ビルドの過程のdh cleanで、ソースツリーが変更されてしまう場合には、 --git-ignore-new を指定します。 ビルド後にはlintianによるパッケージのチェック結果が表示されるので、報告された問題を都度修正するのがよいでしょう。

次に、パッケージのインストールなどに問題がないかテストします。

パッケージのインストールテストにはpiupartsを用います。

% sudo piuparts -d sid  -t /var/cache/pbuilder/build -b /var/cache/pbuilder/unstable-amd64-base.tgz ../build-area/*.deb

紹介した .gbp.conf の設定をしていれば、cloneしたリポジトリと同階層に build-area ディレクトリが作成され、そこにdebパッケージが配置されているはずです。 piupartsによるテストをパスしたら、次はアップロードしましょう。

mentors.d.nへソースパッケージをアップロード

mentors.d.nへアップロードするためのソースパッケージを用意します。

% debuild -S

パッケージに署名をしたら、dputで実際にmentors.d.nへとアップロードします。

% dput mentors ../groonga_8.0.2-1_source.changes 

RFSを送りスポンサーを探す

bugs.debian.orgにスポンサーを探すメールを投げます。

Groonga 8.0.2-1の場合は次のようなbugとして登録しました。

gbpでタグを打つ

特に問題なければあとはunstableへとアップロードされるのを待つだけです。ただし、パッケージング内容にコメントがつくことがあります。 その場合は都度対応してソースパッケージを再びアップロードします。

パッケージの修正が追加で必要になることもあるので、タグを打つのは実際にunstableに入ってからのほうがよいかもしれません。

タグを打つには、以下のコマンドを実行します。

% gbp buildpackage --git-tag --git-debian-branch=debian/unstable

ここまでで、gbpでDebianパッケージのアップデートをリリースするところまでの作業が完了です。

まとめ

今回は、メンテナンスしているパッケージをgbpのやりかたに合わせつつアップデートする方法を紹介しました。

必要最低限のgbpの使い方しか紹介していないので、詳細については、http://honk.sigxcpu.org/projects/git-buildpackage/manual-html/gbp.html を参照してください。

2018-05-10

WebExtensionsによるFirefox用の拡張機能でメニューやパネル風のUIを提供するライブラリ:MenuUI.js

(この記事は、Firefoxの従来型アドオン(XULアドオン)の開発経験がある人向けに、WebExtensionsでの拡張機能開発でのノウハウを紹介する物です。)

XULでは<menupopup>という要素の中に<menuitem><menu>などの要素を置いてネイティブアプリと同じ様式の階層型メニューを実装できました。それに対し、WebExtensionsベースの拡張機能ではUIは基本的にHTMLで作成します。この時に悩み所になるのが、メニューをどうやって実装するかという点です。

HTMLにもmenu要素という物がありますが、これはXULのメニュー関連要素の完全な代替とはなりません。ボタンに対してのポップアップメニューやツールバー上のメニューは本稿執筆時点でFirefoxでは実装されておらず、唯一使用できるコンテキストメニューでの用法についても、専用のコンテキストメニューを実現する物ではなく、あくまで「Webページ上のコンテキストメニューに追加の項目を設ける」という性質の物です。

Firefoxのコンテキストメニューとは切り離された別のメニューを実現するには、今のところHTML(+JavaScript+CSS)でそれらしい見た目と振る舞いのUIを独自に実装するほかありません。実装例自体は既存の物が多数あり、React用Vue用jQuery用など、採用するフレームワークに合わせて選べます。しかし、作りたいアドオンの性質上、フレームワークの導入には気乗りしないという人もいるのではないかと思います。

そこで、このような場面で使える軽量なライブラリとしてMenuUI.jsという物を開発しました。

基本的な使い方

このライブラリは、HTMLファイル中に静的に記述された物か動的に生成された物かを問わず、<ul><li>で構成された入れ子のリストを階層型のメニューとして振る舞わせるという物です。表示例はこんな感じです。 (Tree Style Tabでの使用例)

このライブラリを使ってメニュー風UIを提供するには、まず任意のHTMLファイル内でMenuUI.jsを読み込みます。

<script type="application/javascript" src="./MenuUI.js"></script>

また、それと併せてメニューとして表示するためのリストを以下の要領で用意します。

<ul id="menu">
  <li id="menu-save">保存(&amp;S)</li>
  <li>コピー(&amp;P)
    <ul>
      <li id="menu-copy-title">タイトル(&amp;T)</li>
      <li id="menu-copy-url">&amp;URL</li>
      <li>メタデータ(&amp;M)
        <ul>
          <li id="menu-copy-author">作者名(&amp;A)</li>
          <li id="menu-copy-email">&amp;Eメール</li>
        </ul>
      </li>
    </ul>
  </li>
  <li class="separator"></li>
  <li id="menu-close">閉じる(&amp;C)</li>
</ul>
  • サブメニューを定義したい場合はリストを入れ子にして下さい。
  • この例では、後々どの項目が選択されたかを容易に判別できるようにするために、コマンドとして実行されうる項目にIDを割り当てています。(通例、サブメニューを持つ項目はそれ自体が選択されてもコマンドとしては実行されないため、それらにはIDを割り当てていません。)
  • リストの内容となるテキストがそのままメニュー項目のラベルになります。
    • この時、ラベルの一部に&(静的に記述する場合は実体参照の&amp;)を書いておくと、その次の文字がメニュー項目のアクセスキーになります。

次に、このリストをメニューとして初期化します。以下の要領でMenuUIクラスのインスタンスを作成します。

var menuUI = new MenuUI({
  root: document.getElementById('menu'), // メニューにするリストの最上位の<ul>を指定
  onCommand: (aItem, aEvent) => {
    // 項目が選択された時に実行されるコールバック。
    // ここでは項目のidで処理を振り分けるようにしている。
    switch (aItem.id) {
      case 'menu-save':
        doSave();
        return;
      case 'menu-copy-title':
        doCopy('title');
        return;
      ...
    }
  }
});

作成されたインスタンスは、open()というメソッドを実行するとメニューとして表示されます。ページ上を右クリックした際にブラウザ本来のコンテキストメニューの代わりとして表示したい場合であれば、以下のようにします。

window.addEventListener('contextmenu', aEvent => {
  aEvent.stopPropagation();
  aEvent.preventDefault();
  menuUI.open({
    left: aEvent.clientX,
    top:  aEvent.clientY
  });
});

また、何かのボタンをクリックした時にドロップダウンメニューのように表示させたい場合には、以下のようにボタンのクリック操作を監視した上で、そのボタンなどの要素をopen()メソッドの引数にanchorというプロパティで指定すると、ボタンの位置に合わせてメニューが表示されます。

const button = document.getElementById('button');
button.addEventListener('click', () => {
  menuUI.open({
    anchor: button
  });
});

コンストラクタのオプションやopen()のオプションの詳細な内容については、リポジトリ内のREADMEファイルを参照して下さい。

キーボードでの操作への対応

このライブラリの特長として、キーボード操作への対応に力を入れているという点が挙げられます。以下は、現時点で対応している代表的な操作です。

  • ↑↓カーソルキーで項目のフォーカスを移動
  • →カーソルキーでサブメニューを開く
  • ←カーソルキーでサブメニューを閉じる
  • Escキーでメニューを閉じる
  • Enterキーでフォーカスしている項目を選択(コマンドを実行)
  • メニューのラベルから検出されたアクセスキーで項目を選択(同じアクセスキーの項目が複数ある場合はフォーカス移動のみ)

メニューを開くまではポインティングデバイスを使うが、その後の操作はキーボードで行う、というような場面は意外とあります。既存のライブラリはキーボード操作に対応していなかったり、操作体系が一般的なGUIのメニューではなくWebページ上のリンクに準拠していたりと、「ネイティブアプリのGUIと同じ感覚で使える」事が特長だったXULからの移行においてストレスになる部分があったため、この点にはとりわけ気をつけて開発しています。

まとめ

XULアドオンでのカスタムメニューの代替となる軽量ライブラリであるMenuUI.jsについて、その使い方を解説しました。「以後確認しない」のようなチェックボックスを伴った確認ダイアログを表示するRichConfirm.jsと併せて、Firefox用アドオンの開発にご活用いただければ幸いです。

タグ: Mozilla
2018-05-11

Mozilla Firefox ESR60でのPolicy Engineによるポリシー設定の方法と設定項目のまとめ

FirefoxはESR60以降のバージョンにおいて、法人利用者向けに設定を集中管理する新しい仕組みである「Policy Engine」が導入・有効化されています。Policy Engineで可能な設定の一部は従来のMCD(AutoConfig)と重複していますが、Policy Engineには従来型アドオンによるカスタマイズの代替手段としての性質もあり、MCDではできなかった設定も存在しています。

過去の記事(第一報グループポリシーについての続報)において、Firefox 60のベータ版を対象として設定の手順やその時点で使用できるようになっていた設定項目を紹介してきましたが、この度のFirefox ESR60正式版のリリースに伴い、改めて最新の状況について情報を整理します。

ポリシー設定を反映する2つの方法

WindowsでPolicy Engineを使って設定を集中管理する方法には、以下の2通りがあります。

  • ポリシー定義ファイル(policies.json)を使う
  • Active Directoryのグループポリシーを使う(Windowsのみ)
policies.jsonを使う

この方法を使う場合には、各クライアントPC上のFirefoxのインストール先フォルダ(C:\Program Files\Mozilla FirefoxC:\Program Files (x86)\Mozilla Firefox など)配下にdistributionという名前でフォルダを作成し、さらにその中にpolicies.jsonという名前で以下の内容のテキストファイル(JSON形式)を設置します。

{
  "policies": {
    (ここにポリシー設定を記述する)
  }
}

例えば、後述の"BlockAboutAddons""BlockAboutConfig"を両方とも設定する場合は以下の要領です。

{
  "policies": {
    "BlockAboutAddons": true,
    "BlockAboutConfig": true
  }
}

この方法の利点は、ファイルを配置する事さえできればLinux版およびmacOS版(ファイルはFirefox.appをディレクトリと見なして、その配下に設置する事になります)においても使用できるという点です。

欠点は、設定ファイルを各クライアントに適切に配置しなくてはならないという事と、この方法で設定しただけでは充分に機能しない設定があるという事です。一部の設定項目は、期待通りの結果を得るためには後述のグループポリシーで設定する必要があります。

本記事では、各設定項目の指定はこちらの方法で設定する想定で解説します。

Active Directoryのグループポリシーを使う

Windows版Firefoxでは、Active Directoryのグループポリシーを使ってPolicy Engineの設定を制御することができます。Mozillaの外部プロジェクトとして公開されているポリシーテンプレート*1をダウンロードして展開し、ドメインコントローラの C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions 配下に各ファイルを配置すると、グループポリシーの管理画面上で「コンピューターの構成」および「ユーザーの構成」の「管理用テンプレート」配下にFirefox向けの設定項目が表示されるようになります。各設定項目の働きは、policies.jsonで設定可能な項目に対応しています。

Firefoxの設計上は、同じポリシーがユーザー向けとコンピューター向けの両方に設定されていた場合、ユーザーに設定されたポリシーよりもコンピューターに設定されたポリシーの方が優先的に反映されます。例えば「Block About Config」というポリシーについて、ユーザー向けのポリシーで「有効」と設定していても、コンピューターのポリシーで「無効」と設定していると、このポリシーは「無効」と扱われます。基本的にはコンピューター向けのポリシーのみ設定して運用するとよいでしょう。

なお、2018年5月14日時点では、ポリシーテンプレートはWindows Server 2008以降で使用できるadmx形式のファイルのみが提供されています*2。Windows 2003 ServerをドメインコントローラとしてActive Directoryを運用している場合には、上記のポリシーテンプレートを参考にadm形式のポリシーテンプレートを作成する必要があります。ポリシーテンプレートを用意できない場合は、policies.jsonを各クライアントに設置する方法を取らなくてはなりません。

この方法の利点は、ドメインコントローラ上での操作のみで管理を完結できるという事です。また、こちらの方法で設定した場合には、全ての設定項目が期待通りに機能するというメリットもあります。

欠点は、当然ですが、Active Directoryでドメインを運用中でないと利用できないという点です。ドメインを構築していないような小規模の組織においては、policies.jsonを使う他ないという事になります。

Firefox ESR60で使用できる設定項目

Policy Engineで設定可能な項目はいくつかのカテゴリに分類できます。以下、カテゴリごとにご紹介します。

  • 2018年11月30日:Firefox ESR60.4までのバージョンでの以下のポリシー設定の追加・変更点について追記しました。
    • AppUpdateURL(自動更新の制御)
    • Authentication.AllowNonFQDN(シングルサインオンを許可するための設定)
    • Certificates.Install(証明書のインポート)
    • HardwareAcceleration(様々な機能の無効化)
    • Homepage.StartPage(ホームページの設定)
    • Permissions(Webサイトに与える様々な権限の設定)
    • RequestedLocales(UIの初期状態)
    • SearchEngines.Remove(検索エンジンの設定)
    • SecurityDevices(セキュリティデバイスの設定)
  • 2019年5月15日:Firefox ESR60.6.3までのバージョンでの以下のポリシー設定の追加・変更点について追記しました。
    • 3rdparty(アドオンの制御)
    • CaptivePortal(ネットワーク関係の設定)
    • DefaultDownloadDirectory(UIの初期状態)
    • DNSOverHTTPS(ネットワーク関係の設定)
    • DownloadDirectory(UIの初期状態)
    • ExtensionSettings.*.blocked_install_message(アドオンの制御)
    • ExtensionUpdate(自動更新の制御)
    • FirefoxHome(新規タブページの設定)
    • LocalFileLinks(ネットワーク関係の設定)
    • NetworkPrediction(ネットワーク関係の設定)
    • NewTabPage(新規タブページの設定)
    • OverridePostUpdatePage(ホームページの設定)
    • Preferences(その他の細々とした設定)
    • PromptForDownloadLocation(UIの初期状態)
    • SupportMenu(UIの初期状態)
    • SSLVersionMax(ネットワーク関係の設定)
    • SSLVersionMin(ネットワーク関係の設定)
シングルサインオンを許可するための設定

シングルサインオンに関する設定としては、以下の設定が可能です。
設定は全て"Authentication"配下に定義します。

{
  "policies": {
    ...

    "Authentication": {
      // SPNEGO認証を許可するサイトのリスト。
      // (MCDでの network.negotiate-auth.trusted-uris に相当)
      "SPNEGO": ["www.example.com", "http://www.example.org/", ...],

      // 認証情報の委任を許可するサイトのリスト。
      // (MCDでの network.negotiate-auth.delegation-uris に相当)
      "Delegated": ["www.example.com", "http://www.example.org/", ...],

      // NTLM認証を許可するサイトのリスト。
      // (MCDでの network.automatic-ntlm-auth.trusted-uris に相当)
      "NTLM": ["www.example.com", "http://www.example.org/", ...],

      // 確認証方式でFQDN以外の使用を許可する
      // (Firefox ESR60.2以降)
      "AllowNonFQDN": {
        // SPNEGO認証でFQDN以外の使用を許可
        // (MCDでの network.negotiate-auth.allow-non-fqdn に相当)
        "SPNEGO": true,

        // NTLM認証でFQDN以外の使用を許可
        // (MCDでの network.automatic-ntlm-auth.allow-non-fqdn に相当)
        "NTLM":   true
      }
    },

    ...
  }
}

"SPNEGO""Delegated"、および"NTLM"の各設定は、必要な物だけを設定します。不要な設定は省略して構いません。

自動更新の制御

自動更新の制御に関する設定には、以下の項目があります。

{
  "policies": {
    ...

    // Firefoxの自動更新を禁止する。
    "DisableAppUpdate": true,

    // Firefoxの更新情報の取得先URL
    // (Firefox ESR60.2以降)
    // (MCDでの app.update.url に相当)
    "AppUpdateURL": "https://example.com/update.xml",

    // アドオンの自動更新を禁止する
    // (Firefox ESR60.6.2以降)
    // (MCDでの extensions.update.enabled に相当)
    "ExtensionUpdate": false,

    // システムアドオンの更新を禁止する。
    "DisableSystemAddonUpdate": true,

    ...
  }
}
about: で始まるURIのページへのアクセスを禁止

URIがabout: で始まる特別なページのうちいくつかは、以下の設定でアクセスを禁止する事ができます。

{
  "policies": {
    ...

    // about:addons(アドオンマネージャ)の表示を禁止する。
    // アドオンの設定変更、有効・無効の切り替え、インストール、
    // アンインストールなどの操作を全面的に禁止することになる。
    "BlockAboutAddons": true,

    // about:config(設定エディタ)の表示を禁止する。
    // 設定画面に現れない詳細な設定の変更を禁止することになる。
    // 副作用として、ブラウザコンソールの入力欄も強制的に無効化される。
    "BlockAboutConfig": true,

    // about:profiles(プロファイル管理画面)の表示を禁止する。
    // プロファイルを指定しての起動、アドオンを無効にしての起動などを
    // 禁止することになる。
    "BlockAboutProfiles": true,

    // about:support(トラブルシューティング情報)の表示を禁止する。
    // アドオンを無効にしての起動などを禁止することになる。
    "BlockAboutSupport": true,

    ...
  }
}
初期ブックマーク項目の作成

ポリシー設定を使って、初期状態で任意のブックマーク項目やフォルダを登録済みの状態にする事ができます。

{
  "policies": {
    ...

   // 初期状態で登録しておく追加のブックマーク項目の定義。任意の個数登録可能。
   "Bookmarks": [
     { // ブックマークツールバーにブックマークを作成する場合
       "Title":     "example.com",
       "URL":       "http://www.example.com/",
       "Favicon":   "http://www.example.com/favicon.ico",
       "Placement": "toolbar"
     },

     { // ブックマークツールバーの中にフォルダを作って、その中にブックマークを作成する場合
       "Title":     "example.com",
       "URL":       "http://www.example.com/",
       "Favicon":   "http://www.example.com/favicon.ico",
       "Placement": "toolbar",
       "Folder":    "ツールバー初期項目"
     },

     { // ブックマークメニューにブックマークを作成する場合
       "Title":     "example.org",
       "URL":       "http://www.example.org/",
       "Favicon":   "http://www.example.org/favicon.ico",
       "Placement": "menu"
     },

     { // ブックマークメニューの中にフォルダを作って、その中にブックマークを作成する場合
       "Title":     "example.org",
       "URL":       "http://www.example.org/",
       "Favicon":   "http://www.example.org/favicon.ico",
       "Placement": "menu",
       "Folder":    "メニュー初期項目"
     },

     ...
   ],

   // Firefox自体の初期ブックマーク項目を作成しない。
   // (「よく見るページ」などのスマートブックマーク項目を除く)
   // この設定は初回起動時・新規プロファイル作成時にのみ反映され、
   // 既に運用中のプロファイルには反映されない(作成済みの初期ブックマーク項目は削除されない)。
   "NoDefaultBookmarks": true,

    ...
  }
}
証明書のインポート

ルート証明書の自動インポートに関しては、以下の設定が可能です。
設定は全て"Certificates"配下に定義します。

{
  "policies": {
    ...

    "Certificates": {
      // 管理者によってシステムに配布されたルート証明書をFirefoxの証明書データベースにインポートする。
      // (WindowsのActive Directoryのグループポリシーで配布されたルート証明書をインポートする)
      "ImportEnterpriseRoots": true,

      // Firefoxの証明書データベースにインポートするルート証明書のファイル名
      // (Firefox ESR60.4以降)
      "Install": [
        "example1.pem",
        "example2.crt",
        ...
      ]
    },

    ...
  }
}

"ImportEnterpriseRoots"による自動インポートは、Windowsのレジストリ上の特定の位置に存在するルート証明書(Active Directoryのグループポリシーで配布された証明書)のみが対象となります。
ユーザーが自分の権限で証明書データベースに登録したルート証明書はインポートされません。

Firefox ESR60.4以降のバージョンでは、Active Directoryを運用していない環境やWindows以外の環境でも、ファイルからルート証明書を自動インポートさせることができます。

  • Windows:
    • %AppData%\MozillaC:\Users\(ユーザー名)\AppData\Roaming\Mozilla\Certificates
    • %LocalAppData%\MozillaC:\Users\(ユーザー名)\AppData\Local\Mozilla\Certificates
  • macOS
    • /Users/(username)/Library/Application Support/Mozilla/Certificates
    • /Library/Application Support/Mozilla/Certificates
  • Linux
    • /home/(username)/.mozilla/certificates
    • /user/lib/mozilla/certificates

上記のいずれかの位置にPEM形式の証明書ファイルを設置し、ファイル名を"Install"に列挙しておくと、それらの証明書がFirefoxの証明書データベースへ自動的にインポートされます。

Cookieの保存の可否と有効期限

Cookieに関する設定は、以下の物があります。
設定は全て"Cookies"配下に定義します。

{
  "policies": {
    ...

    "Cookies": {
      // 指定のWebサイト(オリジンで指定)でCookie、IndexedDB、
      // Web Storage、およびService Worker用Cacheを保存する。
      // (任意に無効化はできない)
      "Allow": ["http://example.com", "https://example.org:8080", ...],

      // 指定のWebサイト(オリジンで指定)でCookie、IndexedDB、
      // Web Storage、およびService Worker用Cacheを保存する。
      // (任意に無効化はできない)
      // また、これらのホストに保存済みのCookieがあった場合、それらは削除される。
      "Block": ["http://example.com", "https://example.org:8080", ...],

      // サードパーティCookieかどうかに関わらず、全てのCookieを一律で拒否する。
      "Default": false,

      // サードパーティによるCookieの受け入れ可否。
      // 以下の3つの中からいずれかを指定する。
      //  * "always":       全て受け入れる。
      //  * "never":        全く受け入れない。
      //  * "from-visited": 既に保存済みのサードパーティCookieがある場合のみ受け入れる。
      // (MCDでの network.cookie.cookieBehavior に相当)
      "AcceptThirdParty": "always",

      // 全てのCookieについて「Firefoxを終了するまでを有効期限とし、
      // Webサイトが指定した保持期限を無視する。
      // (MCDでの network.cookie.lifetimePolicy に相当)
      "ExpireAtSessionEnd": true,

      // Cookieに関する設定のユーザーによる変更を禁止する。
      "Locked": true
    },

    ...
  }
}
様々な機能の無効化

機能の無効化に関する設定には、以下の項目があります。

{
  "policies": {
    ...

    // PDF.jsを無効化する。
    // (MCDでの pdfjs.disabled に相当)
    "DisableBuiltinPDFViewer": true,

    // 開発ツールを無効化する。
    // メニュー項目、キーボードショートカットの両方とも無効化する。
    // (MCDでの devtools.policy.disabled および
    //   devtools.chrome.enabled に相当)
    "DisableDeveloperTools": true,

    // フィードバックの送信、詐欺サイトの誤検出の報告を禁止する。
    "DisableFeedbackCommands": true,

    // FirefoxアカウントとSyncを無効化する。
    "DisableFirefoxAccounts": true,

    // Firefox Screenshotsを無効化する。
    "DisableFirefoxScreenshots": true,

    // Firefoxの新機能のテストへの参加( https://support.mozilla.org/ja/kb/shield )を禁止する。
    "DisableFirefoxStudies": true,

    // 「忘れる」ボタンを無効化する。
    "DisableForgetButton": true,

    // フォームの入力履歴の保存とオートコンプリートを無効化する。
    // (MCDでの browser.formfill.enable に相当)
    "DisableFormHistory": true,

    // マスターパスワードの設定を禁止する。
    "DisableMasterPasswordCreation": true,

    // Pocketを無効化する。
    // (MCDでの extensions.pocket.enabled に相当)
    "DisablePocket": true,

    // プライベートブラウジング機能の使用を禁止する。
    "DisablePrivateBrowsing": true,

    // 他のブラウザからのブックマークや設定のインポート機能を無効化する。
    // (ただし、ESR60時点では初回起動時の設定インポートは無効化されない)
    "DisableProfileImport": true,

    // しばらくぶりにFirefoxを起動した際のプロファイルのリフレッシュ操作(データの消去)の提案と、
    // about:support(トラブルシューティング情報)からの手動でのリフレッシュ操作を無効化する。
    // (MCDでの browser.disableResetPrompt に相当)
    "DisableProfileRefresh": true,

    // クラッシュからの復帰時と自動更新の時以外で、
    // セーフモードでの起動(アドオンを無効化しての起動)を禁止する。
    // ただし、コマンドライン引数でのセーフモードまで無効化するにはグループポリシーでの設定が必要。
    "DisableSafeMode": true,

    // セキュリティ警告を敢えて無視することによる危険な操作の実行を、完全に禁止する。
    "DisableSecurityBypass": {
      // 証明書の警告の例外を登録するボタンを隠して、
      // 例外を絶対に登録できないようにする。
      // (MCDでの security.certerror.hideAddException に相当)
      "InvalidCertificate": true,

      // 詐欺サイト等の警告における「危険性を無視」リンクを隠して
      // コンテンツを絶対に表示できないようにする。
      // (MCDでの browser.safebrowsing.allowOverride=false に相当)
      "SafeBrowsing": true
    },

    // 画像をコンテキストメニューからデスクトップの壁紙に設定することを禁止する。
    "DisableSetDesktopBackground": true,

    // 統計情報の収集・送信を禁止する。
    // (MCDでの datareporting.healthreport.uploadEnabled および
    //   datareporting.policy.dataSubmissionEnabled に相当)
    "DisableTelemetry": true,

    // 起動時に既定のブラウザにするかどうかを確認しない。
    // (MCDでの browser.shell.checkDefaultBrowser に相当)
    // 既定のブラウザに設定できなくする設定、ではないことに注意。
    "DontCheckDefaultBrowser": true,

    // パスワードマネージャによるパスワードの保存を禁止する。
    // (MCDでの signon.rememberSignons に相当)
    "OfferToSaveLogins": false,

    // ハードウェアアクセラレーションを無効化する。
    // (Firefox ESR60.2以降)
    // (MCDでの layers.acceleration.disabled に相当)
    "HardwareAcceleration": false,

    ...
  }
}

DisableSafeModeのみ、policies.jsonで設定した場合とグループポリシーで設定した場合の効果に差異があり、セーフモードでの起動をより広範に禁止したい場合にはグループポリシーで設定する必要があります。
何らかの理由でグループポリシーを使用できないものの、セーフモードでの起動をより広範に禁止したいという場合は、レジストリを編集してグループポリシーが使われている状況を再現する必要があります。
具体的には、HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Mozilla\Firefoxまたは
HKEY_CURRENT_USER\SOFTWARE\Policies\Mozilla\FirefoxDWORD型で DisableSafeModeという名前の値を作成し、データを1に設定して下さい。

(実際にレジストリに情報を登録した状態)

UIの初期状態

FirefoxのUIの初期状態を変更する設定としては、以下の項目があります。

{
  "policies": {
    ...

    // 初期状態でブックマークツールバーを表示する。
    "DisplayBookmarksToolbar": true,

    // 初期状態でメニューバーを表示する。
    "DisplayMenuBar": true,

    // 検索ツールバーをロケーションバーと統合するかどうか。
    //  * "unified":  統合する(Firefox ESR60以降の初期状態)
    //  * "separate": 分離する(Firefox ESR52以前の初期状態)
    "SearchBar": "separate",

    // UIに使用するロケール
    // (Firefox ESR60.3以降)
    // http://l10n.mozilla-community.org/webdashboard/ に列挙されている言語名を指定し、
    // その中で言語パックがすでにインストール済みの物が使われる。
    // (MCDでの intl.locale.requested に相当)
    "RequestedLocales": [
      "ja",
      "en-US",
      ...
    ],

    // ファイルの既定のダウンロード先フォルダ
    // (Firefox ESR68以降)
    // (MCDでの browser.download.dir に相当)
    "DefaultDownloadDirectory": "(フォルダのパス)",

    // ファイルの固定のダウンロード先フォルダ
    // (Firefox ESR68以降)
    // (MCDでの browser.download.dir に相当)
    "DownloadDirectory": "(フォルダのパス)",

    // 常にダウンロード先フォルダを尋ねる
    // (Firefox ESR68以降)
    // (MCDでの browser.download.useDownloadDir=false に相当)
    "PromptForDownloadLocation": true,

    // 「ヘルプ」メニュー配下から辿れる独自のサポートページへのリンク
    // (Firefox ESR60.6.2以降)
    "SupportMenu": {
      "Title":     "タイトル",
      "URL":       "https://example.com/",
      "AccessKey": "H"
    },

    ...
  }
}

"DisplayBookmarksToolbar""DisplayMenuBar"、および"SearchBar"については、ユーザーが任意に状態を変更した場合はそちらが優先されます。
(強制的にその状態に固定する、ということはできません。)

プライバシー情報の取り扱いに関わる設定

プライバシー情報に関する設定は、以下の項目があります。
トラッキング防止機能の設定は"EnableTrackingProtection"配下に定義します。

{
  "policies": {
    ...

    "EnableTrackingProtection": {
      // トラッキング防止機能の有効無効。
      //  * true:  有効(トラッキングを防止する)
      //  * false: 無効(トラッキングを許容する)
      // (MCDでの privacy.trackingprotection.enabled および
      //   privacy.trackingprotection.pbmode.enabled に相当)
      "Value": false,

      // トラッキング防止機能の、ユーザーによる設定変更の可否。
      //  * true:  ユーザーの設定変更を禁止(設定を固定する)
      //  * false: ユーザーの設定変更を許可
      "Locked": true
    },

    // Firefox終了時に、その都度履歴やCookieなどのプライバシー情報を全て消去する。
    // (MCDでの privacy.sanitize.sanitizeOnShutdown に相当)
    "SanitizeOnShutdown": true,

    ...
}
アドオンの制御

アドオンの制御に関する設定には、以下の項目があります。
管理者によるアドオンのインストールやアンインストールの制御は"Extensions"配下に、ユーザーによるインストールの可否に関する設定は"InstallAddonsPermission"配下に定義します。

{
  "policies": {
    ...

    "Extensions": {
      // 自動的にインストールするアドオンのXPIファイルの位置。
      // ("InstallAddonsPermission"配下の"Default"がfalseであってもインストールされる)
      "Install": [
        // URLでの指定
        "https://example.com/my-addon.xpi",
        // ファイルパスでの指定
        "C:\\Path\\To\\XPI\\File\\my-another-addon.xpi",
        ...
      ],

      // インストールされていた場合に自動的にアンインストールするアドオンのID。
      "Uninstall": [
        "my-legacy-addon@example.com",
        "my-obsolete-addon@example.org",
        ...
      ],

      // アンインストール、無効化を禁止するアドオンのID。
      // (設定の変更は可能)
      "Locked": [
        "my-security-addon@example.com",
        "my-privacy-addon@example.org",
        ...
      ]
    },

    // アドオンのインストールの可否に関する制御。
    "InstallAddonsPermission": {
      // アドオンのインストール時に警告を行わないページ。
      // (オリジンで指定、`https`のみ有効)
      "Allow": ["https://example.com", "https://example.org:8080", ...],

      // ユーザーによるアドオンのインストールを禁止する。
      // (MCDでの xpinstall.enabled に相当)
      "Default": false
    },

    // アドオンごとの固有の設定
    "ExtensionSettings": {
      "example@example.com": { // アドオンのIDを指定
        // インストールをブロックした時の特別なメッセージ
        // (Firefox ESR68以降)
        "blocked_install_message": "このアドオンは使用禁止です"
      }
    }

    // アドオンごとのManaged Storage
    // (Firefox ESR68以降)
    "3rdparty": {
      "Extensions": {
        "ieview-we@clear-code.com": { // アドオンのIDを指定
          "ieapp": "C:\\Program Files (x86)\\Internet Explorer\\iexplore.exe",
          "ieargs": ""
        }
      }
    }

    ...
}

"Extensions""Install"で指定したアドオンは、実行時のユーザープロファイル内にインストールされます。"Extensions""Uninstall"も、ユーザープロファイル内にあるアドオンが対象となります。

すべてのユーザーで常に特定のアドオンがインストールされた状態としたい場合は、特定のフォルダにファイルを設置することによるサイドローディングでインストールする必要があります。

これらの方法でインストールおよびアンインストールしたアドオンは、Firefox ESR60.4以降のバージョンであればポリシーの再設定によって再インストールさせることができます。
それ以前のバージョンでは、一度アンインストールしたアドオンをこの方法で再インストールさせることはできません。

Adobe Flashプラグインの制御

Flashプラグインの制御については、以下の項目があります。
設定は全て"FlashPlugin"配下に定義します。

{
  "policies": {
    ...

    "FlashPlugin": {
      // 指定のWebサイト(オリジンで指定)でFlashを
      // Click to Play無しで自動実行する。
      // (任意に無効化はできない)
      "Allow": ["http://example.com", "https://example.org:8080"],

      // 指定のWebサイト(オリジンで指定)でFlashの実行を禁止する。
      // (任意に無効化はできない)
      "Block": ["http://example.com", "https://example.org:8080"],

      // 初期状態でClick to Play無しで自動実行するかどうか。
      // (MCDでの plugin.state.flash に相当、未定義でClick to Play)
      "Default": true,

      // 設定の変更を許容するかどうか
      // (MCDでの plugin.state.flash の固定に相当)
      "Locked": true
    },

    ...
}
ホームページの設定

起動時に表示されるページの設定には、以下の項目があります。
ホームページに関する設定は全て"Homepage"配下に定義します。

{
  "policies": {
    ...

    "Homepage": {
      // ホームページのURI(複数タブを設定する場合は最初のタブの内容)
      // (MCDでの browser.startup.homepage および
      //    に対応)
      "URL": "http://example.com",

      // ホームページを複数設定する場合の、2番目以降のタブの内容
      "Additional": ["https://example.org:8080", ...],

      // Firefoxの毎起動時の初期状態
      // (Firefox ESR60.4以降)
      // 以下のいずれかを指定する。
      //   "none":            空のページを表示(MCDでの browser.startup.page=0 に対応)
      //   "homepage":        ホームページを表示(MCDでの browser.startup.page=1 に対応)
      //   "previous-session":前回終了時の状態を復元(MCDでの browser.startup.page=3 に対応)
      // Firefox ESR60.4以前のバージョンでは、"URL" が設定されていると強制的に
      // "StartPage":"homepage" に相当する状態となります。
      "StartPage": "homepage",

      // これらの設定のユーザーによる変更を禁止する
      "Locked": true
    },

    // 初回起動後に1回だけ表示されるページのURL。
    // (MCDでの startup.homepage_welcome_url に相当)
    "OverrideFirstRunPage": "http://www.example.com/",

    // 更新後に1回だけ表示されるページのURL。空にすると、タブを開かない。
    // (MCDでの startup.homepage_override_url に相当)
    "OverridePostUpdatePage": "http://www.example.com/",

    ...
}
新規タブページの設定

新しい空のタブを開いた時の内容の設定には、以下の項目があります。

{
  "policies": {
    ...

    // 新規タブを完全な空白ページにする
    // (Firefox ESR68以降)
    // (MCDでの browser.newtabpage.enabled に相当)
    "NewTabPage": false,

    // Activity Streamの制御
    "FirefoxHome": {
      // 検索窓を非表示にする
      // (Firefox ESR68以降)
      // (MCDでの browser.newtabpage.activity-stream.showSearch に相当)
      "Search": false,

      // 「トップサイト」を非表示にする
      // (Firefox ESR68以降)
      // (MCDでの browser.newtabpage.activity-stream.feeds.topsites に相当)
      "TopSites": false,

      // 「ハイライト」を非表示にする
      // (Firefox ESR68以降)
      // (MCDでの browser.newtabpage.activity-stream.feeds.section.highlights に相当)
      "Highlights": false,

      // 「トップストーリー」を非表示にする
      // (Firefox ESR68以降)
      // (MCDでの browser.newtabpage.activity-stream.feeds.section.topstories に相当)
      "Pocket": false,

      // 「スニペット」を非表示にする
      // (Firefox ESR68以降)
      // (MCDでの browser.newtabpage.activity-stream.feeds.snippets に相当)
      "Snippets": false,

      // ユーザーによる設定の変更を禁止する。
      // (Firefox ESR68以降)
      "Locked": true
    },

    ...
}
ポップアップブロックの制御

ポップアップブロック機能の制御に関しては、以下の設定項目があります。
設定は全て"PopupBlocking"配下に定義します。

{
  "policies": {
    ...

    "PopupBlocking": {
      // window.open() によるポップアップを確認なしで許可するWebサイト。
      // オリジンで指定し、任意に無効化はできない。
      "Allow": ["http://example.com", "https://example.org:8080"],

      // ポップアップブロック機能を初期状態で無効化する。
      // (MCDでの dom.disable_open_during_load に相当)
      "Default": false,

      // ユーザーによる設定の変更を禁止する。
      "Locked": true
    },

    ...
}
Webサイトに与える様々な権限の設定

ポップアップブロックやアドオンのインストール可否以外の、Webサイトに与える様々な権限の設定には、以下の項目があります。

{
  "policies": {
    ...

    "Permissions": {

      // Webカメラ
      // (Firefox ESR60.2以降)
      "Camera": {
        // Webカメラの権限要求無しで使用を許可するWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Allow": ["https://example.com", "https://example.org:8080", ...],

        // Webカメラの使用を禁止し、権限の確認もさせないWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Deny": ["https://example.com", "https://example.org:8080", ...],

        // Webカメラの使用を初期状態で禁止し、権限の確認もしないようにする。
        // (true はMCDでの permissions.default.camera=2 に、
        //   false は permissions.default.camera=0 に相当)
        "BlockNewRequests": true,

        // BlockNewRequestsの設定をユーザーが変更して上書きする事を禁止する。
        "Locked": true
      },

      // マイク
      // (Firefox ESR60.2以降)
      "Microphone": {
        // マイクの権限要求無しで使用を許可するWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Allow": ["https://example.com", "https://example.org:8080", ...],

        // マイクの使用を禁止し、権限の確認もさせないWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Deny": ["https://example.com", "https://example.org:8080", ...],

        // マイクの使用を初期状態で禁止し、権限の確認もしないようにする。
        // (true はMCDでの permissions.default.microphone=2 に、
        //   false は permissions.default.microphone=0 に相当)
        "BlockNewRequests": true,

        // BlockNewRequestsの設定をユーザーが変更して上書きする事を禁止する。
        "Locked": true
      },

      // 位置情報
      // (Firefox ESR60.2以降)
      "Location": {
        // 位置情報の権限要求無しで使用を許可するWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Allow": ["https://example.com", "https://example.org:8080", ...],

        // 位置情報の使用を禁止し、権限の確認もさせないWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Deny": ["https://example.com", "https://example.org:8080", ...],

        // 位置情報の使用を初期状態で禁止し、権限の確認もしないようにする。
        // (true はMCDでの permissions.default.geo=2 に、
        //   false は permissions.default.geo=0 に相当)
        "BlockNewRequests": true,

        // BlockNewRequestsの設定をユーザーが変更して上書きする事を禁止する。
        "Locked": true
      },

      // デスクトップ通知
      // (Firefox ESR60.2以降)
      "Notifications": {
        // デスクトップ通知の権限要求無しで使用を許可するWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Allow": ["https://example.com", "https://example.org:8080", ...],

        // デスクトップ通知を禁止し、権限の確認もさせないWebサイト。
        // オリジンで指定し、任意に無効化はできない。
        "Deny": ["https://example.com", "https://example.org:8080", ...],

        // デスクトップ通知を初期状態で禁止し、権限の確認もしないようにする。
        // (true はMCDでの permissions.default.desktop-notification=2 に、
        //   false は permissions.default.desktop-notification=0 に相当)
        "BlockNewRequests": true,

        // BlockNewRequestsの設定をユーザーが変更して上書きする事を禁止する。
        "Locked": true
      }

    },

    ...
}
ネットワーク関係の設定

ネットワーク接続、通信に関する設定は以下の項目があります。

{
  "policies": {
    ...

    // 認証が必要なWiFiアクセスポイントを検出した時に、認証用のタブを自動的に開かない
    // (Firefox ESR60.6.2以降)
    // (MCDでの network.captive-portal-service.enabled に相当)
    "CaptivePortal": false,

    // DNS over HTTPSの設定
    // (Firefox ESR68以降)
    "DNSOverHTTPS": {
      // DNS over HTTPSを有効にする
      // (true はMCDでの network.trr.mode=2 に、
      //   false は network.trr.mode=5 に相当)
      "Enabled": true,

      // DNS over HTTPSの問い合わせ先
      // (MCDでの network.trr.uri に相当)
      "ProviderURL": "https://mozilla.cloudflare-dns.com/dns-query".

      // DNS over HTTPSの設定をユーザーが変更して上書きする事を禁止する。
      "Locked": true
    },

    // DNSプリフェッチを無効化する
    // (Firefox ESR60.6.2以降)
    // (MCDでの network.dns.disablePrefetch=true,
    //   network.dns.disablePrefetchFromHTTPS=true に相当)
    "NetworkPrediction": false,

    // リンク先としてローカルファイルの読み込みを許可するページ
    // (MCDでの capability.policy.policynames=localfilelinks_policy,
    //   capability.policy.localfilelinks_policy.checkloaduri.enabled=allAccess,
    //   capability.policy.localfilelinks_policy.sites=(スペース区切りのURL列) に相当)
    "LocalFileLinks": [
      "http://example.com",
      "http://example.net",
      ...
    ],

    // 使用を許可するSSL/TLSの最大バージョン
    // (Firefox ESR60.5.3以降)
    // (MCDでの security.tls.version.max=1~4 に相当)
    "SSLVersionMax": "tls1.3", // "tls1", "tls1.1", "tls1.2", "tls1.3" のいずれか

    // 使用を許可するSSL/TLSの最小バージョン
    // (Firefox ESR60.5.3以降)
    // (MCDでの security.tls.version.min=1~4 に相当)
    "SSLVersionMin": "tls1", // "tls1", "tls1.1", "tls1.2", "tls1.3" のいずれか

    ...
  }
}
プロキシの設定

プロキシに関する設定は以下の項目があります。
設定は全て"Proxy"配下に定義します。

{
  "policies": {
    ...

    "Proxy": {
      // プロキシを使用するかどうか。
      //  * "none":       プロキシを使用しない。
      //  * "system":     システムで設定されたプロキシ設定に従う。
      //                  (Windowsであれば「インターネットオプション」の設定)
      //  * "autoDetect": 接続しているネットワークのDHCPで通知されたWPADの設定に従う。
      //  * "autoConfig"  以降の項目で指定されたPACファイルを使用する。
      //  * "manual":     以降の項目での個別の設定に従う。
      // (MCDでの network.proxy.type に相当)
      "Mode": "none",

      // "Mode":"autoConfig"の時に使用するPACファイルの取得先URL。
      // (MCDでの network.proxy.autoconfig_url に相当)
      "AutoConfigURL": "file://///fileserver/proxyl.pac",

      // HTTPで使用するプロキシのホストとポート番号。
      // (MCDでの network.proxy.http と
      //   network.proxy.http_port に相当)
      "HTTPProxy": "192.168.0.1:50080",

      // SSL/TLSで使用するプロキシのホストとポート番号。
      // (MCDでの network.proxy.ssl と
      //   network.proxy.ssl_port に相当)
      "SSLProxy": "192.168.0.1:50443",

      // FTPで使用するプロキシのホストとポート番号。
      // (MCDでの network.proxy.ftp と
      //   network.proxy.ftp_port に相当)
      "FTPProxy": "192.168.0.1:50022",

      // SOCKSで使用するプロキシのホストとポート番号。
      // (MCDでの network.proxy.socks と
      //   network.proxy.socks_port に相当)
      "SOCKSProxy": "192.168.0.1:51080",

      // SOCKSのバージョン。4または5のみ有効。
      // (MCDでの network.proxy.socks_version に相当)
      "SOCKSVersion": 4,

      // HTTPのプロキシを他の全てのプロトコルに使用する。
      // (MCDでの network.proxy.share_proxy_settings に相当)
      "UseHTTPProxyForAllProtocols": true,

      // プロキシを使用しないホスト。
      // (MCDでの network.proxy.no_proxies_on に相当)
      "Passthrough": "localhost,127.0.0.1,...",

      // DNSへの問い合わせにもプロキシを使用する。
      // (MCDでの network.proxy.socks_remote_dns に相当)
      "UseProxyForDNS": true,

      // プロキシに自動的にログインする。
      // (MCDでの signon.autologin.proxy に相当)
      "AutoLogin": true,

      // ユーザーによる設定の変更を禁止する。
      "Locked": true
    },

    ...
}
検索エンジンの設定

設定は全て"SearchEngines"配下に定義します。

{
  "policies": {
    ...

    "SearchEngines": {
      // 初期状態で検索バー用に登録しておく検索エンジンのリスト。
      "Add": [
        {
          "Name":               "検索エンジンの表示名",
          "IconURL":            "https://example.com/favicon.ico",
          "Alias":              "ex",
          "Description":        "検索エンジンの説明文",
          "Method":             "GET",
          // POSTメソッドの場合の送信内容
          // (Firefox ESR68以降)
          "PostData":           "q={searchTerms}&...",
          "URLTemplate":        "https://example.com/search?q={searchTerms}",
          "SuggestURLTemplate": "https://example.com/suggest?q={searchTerms}"
        },
        ...
      ],

      // 削除する検索エンジンのリスト。
      // (Firefox ESR60.2以降)
      "Remove": [
        "削除する検索エンジンの表示名1",
        "削除する検索エンジンの表示名2",
        ...
      ],

      // 指定した名前の検索エンジンを規定の検索エンジンにする。
      "Default": "Google",

      // 検索エンジンの追加を禁止する。
      "PreventInstalls": true
    },

    ...
}

検索エンジンは、ESR60.xではHTTP MethodがGETである物のみ使用可能です(ESR68以降からはPOSTも使用可能です)。

検索語句は、Firefox ESR60.3.1以降では常にUTF-8でエンコードされます。それ以前のバージョンでは常にCP1252となる不具合(Bug 1463684)があるため、残念ながら日本語の検索クエリは文字化けしてしまい検索できません。日本語の検索を行う前提であれば、Firefox ESR60.3.1以降は必須という事になります。

"Alias"は、検索エンジンに設定するキーワードです。キーワードが設定されている検索エンジンは、ロケーションバーでex 検索したい語句のようにキーワードに続けて語句を入力する形でも呼び出せるようになります。

Firefox ESR60.1以前のバージョンでは、一度インストールされた検索エンジンの設定はポリシー設定を変えても反映されません(Bug 1453350)。文字化けの件と併せても、検索エンジン関係のポリシー設定はFirefox ESR60.3.1以降でのみ実用に足ると言えます。

セキュリティデバイスの設定

ポリシー設定を使うと、ICカードリーダーなどをFirefoxから使用するために必要なセキュリティデバイス(を使用するために必要なライブラリ)の登録を行えます。
設定は全て"SecurityDevices"配下に定義します。

{
  "policies": {
    ...

    // 自動的に登録するセキュリティデバイス名と、
    // ライブラリのフルパスの一覧
    // (Firefox 60.4以降)
    "SecurityDevices": {
      "デバイス名1": "C:\\Path\\To\\Library.dll",
      "デバイス名2": "/path/to/library.so",
      ...
    },

    ...
}
簡易的なアクセス制限

設定は全て"WebsiteFilter"配下に定義します。

{
  "policies": {
    ...

    "WebsiteFilter": {
      // ブロックする対象のURLを示すマッチパターン。
      // (詳細は https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Match_patterns を参照)
      // ESR60時点では、http:またはhttps:で始まるサイトのみが対象で、
      // 最大1000項目まで指定可能。
      "Block": [
        "https://twitter.com/*",
        "https://*.twitter.com/*",
        ...
      ],

      // ブロック対象の例外とするURLを示すマッチパターン。
      "Exceptions": [
        "https://twitter.com/about",
        ...
      ]
    },

    ...
}
その他の細々とした設定

いくつかの設定項目については、MCDの設定名をそのまま使用して設定を固定できます。
設定は全て"Preferences"配下に定義します。

{
  "policies": {
    ...

    "Preferences": {
      // 国際化ドメインを必ずpunycode形式で表示する
      // (Firefox ESR68以降)
      "network.IDN_show_punycode": true,

      // ロケーションバーへの入力内容が1単語のみの時、検索を実行する前にローカルドメインのホスト名として名前解決を試みる
      // (Firefox ESR68以降)
      "browser.fixup.dns_first_for_single_words": true,

      // ディスクキャッシュの格納先フォルダ
      // (Firefox ESR68以降)
      "browser.cache.disk.parent_directory": "C:\\Path\\To\\Folder",

      // ロケーションバーの候補に現在開かれているタブを表示しない
      // (Firefox ESR68以降)
      "browser.urlbar.suggest.openpage": false,

      // ロケーションバーの候補に履歴項目を表示しない
      // (Firefox ESR68以降)
      "browser.urlbar.suggest.history": false,

      // ロケーションバーの候補にブックマーク項目を表示しない
      // (Firefox ESR68以降)
      "browser.urlbar.suggest.bookmark": false
    },

    ...
}

まとめ

以上、Firefox ESR60から使用可能となったPolicy Engineによるポリシー設定について、ESR60.0時点での状況を解説しました。

Policy Engine機能の実装はFirefox 59のリリース以後から急ピッチで進められたため、Firefox ESR60.0の時点では機能不足や不具合がまだまだ目立つ状況と言わざるを得ません。ただ、通常Firefoxのセキュリティアップデートはセキュリティに関わる変更のみが反映されますが、Policy EngineもESR60も法人利用者のための機能である事から、Policy Engineの不具合は、今後ESR60のセキュリティアップデートの中で修正されていく可能性もあります*3。最新の動向に注意しながら使っていきましょう。

ちなみに、ESR60時点で実装されているポリシー設定のうち、以下の機能はクリアコード在籍のエンジニアによって実装されました。
日本での法人利用の中で大きな需要があるポリシー設定については、今後も積極的に実装の提案を行っていきたいと考えています。

*1 現時点では言語リソースは英語用のみが提供されています。

*2 Windows Server 2003ドメインでもこのポリシーテンプレートで行われた設定は有効ですが、ドメインコントローラはWindows Server 2008以降のバージョンである必要があります。

*3 Policy Engineの開発を主導していた方によるPolicy Engineの紹介記事でも、ESR60のセキュリティアップデートの中でポリシーの追加や修正を行っていくことが予告されています。実際に、ESR60向けのブランチにおけるポリシーの実装ファイルの変更履歴を見ると、ESR60のリリース以後も様々な変更が反映されています。

タグ: Mozilla
2018-05-12

キー入力内容を手軽にGIFアニメーションにするには

はじめに

GUIのアプリケーションの操作内容を説明するときに、テキストであれこれ説明するよりも、実際に操作している映像を示したほうがわかりやすいことがあります。 Vimで単語を囲む方法をいくつかでも使っていた、peekscreenkeyによるGIFアニメーションの作成方法について紹介します。

peekとscreenkeyをインストールする

必要なパッケージをインストールします。aptでそれぞれインストール可能です。

$ sudo apt install peek screenkey

screenkeyはDebian stretch以降であればaptでインストールできます。peekについてはDebian buster以降であればaptでインストールできるようになるはずです。*1

screenkeyを起動する

入力したキーの内容を画面に表示してくれるのがscreenkeyです。screenkeyは以下のコマンドを実行して起動します。

$ screenkey

何もオプションを指定しない場合、入力したキーが画面下部に黒背景に白文字で表示されます。 画面幅いっぱいに表示されるので、特定の領域にのみ表示したい場合には表示位置を明示的に指定するとよいでしょう。 そのためのオプションとして--geometryがあります。

以下は、--geometryオプションでウィンドウ内にvimのキー入力を表示させています。

sceenkeyの実行画面

peekを起動する

指定した範囲をキャプチャしてくれるのがpeekです。peekは以下のコマンドを実行して起動します。

$ peek

peekを起動すると画面キャプチャ対象を指定するためのウィンドウが表示されます。 また、画面左上にはキャプチャをどの形式で保存するかを指定するコンボボックスが表示されます。

peekの起動画面

Record as GIF をクリックすると指定範囲のキャプチャを開始します。キャプチャ開始後にStopをクリックすると指定したフォーマットでファイルを保存することができます。

まとめ

今回は、peekとscreenkeyによるGIFアニメーションの作成方法について紹介しました。 GIFアニメーションを作成する場合の方法の一つとして参考にしてみてください。

*1 いずれも公式リポジトリからインストールする場合。Ubuntuの場合、PPAからインストールすることもできます。

2018-05-13

WebExtensionsによるFirefox用の拡張機能で、キーボードショートカットの変更用UIを提供するライブラリ:ShortcutCustomizeUIMenuUI.js

2019年6月4日追記:Firefox 66以降のバージョンではFirefoxのアドオンマネージャからアドオンのショートカットを変更できるようになりました。このライブラリはもう不要となっています。

(この記事は、Firefoxの従来型アドオン(XULアドオン)の開発経験がある人向けに、WebExtensionsでの拡張機能開発でのノウハウを紹介する物です。)

従来型のアドオンでキーボードショートカットを実現する方法には、XULの<key>要素を使う方法と、JavaScriptでキーイベントを捕捉する方法の2通りがありました。WebExtensionsでは、前者はmanifest.jsoncommandsでショートカットを定義する方法、後者はcontent scriptで実装する方法がそれぞれ対応します。ブラウザウィンドウのどこにフォーカスがあっても動作するキーボードショートカットを実現する方法としては、前者の方法が唯一の選択肢となります*1

Firefox 60以降のバージョンではmanifest.jsonで定義されたキーボードショートカットを後から任意の物に変更できるようになったのですが、Google Chromeでは拡張機能が定義したキーボードショートカットを横断して制御できる設定画面をChrome自体が提供しているのに対し、Firefox 60にはまだその機能がありません。実際にキーボードショートカットを変更するためには、commands.updateという機能を使って各アドオンが自前で設定UIを提供する必要があります。

そこで、Firefox本体で設定UIが提供されるようになるまでのつなぎとして、キーボードショートカットの変更のためのUIを提供する軽量なライブラリ ShortcutCustomizeUI.jsを開発しました。

使い方

このライブラリは、以下の2つの機能を含んでいます。

  • キーボードショートカットの設定用UIを生成する
  • 既定のキーボードショートカットを割り当て解除できるようにする

順番に説明してきます。

キーボードショートカットの設定用UIを生成する

このライブラリは、キーボードショートカットの変更用UIとして機能するHTMLのコード片をDocumentFragmentとして生成する機能を含んでいます。まず、設定画面を提供するHTMLファイルにShortcutCustomizeUI.jsを読み込ませて下さい。

<script type="application/javascript" src="./ShortcutCustomizeUI.js"></script>

このファイルを読み込むとShortcutCustomizeUIというオブジェクトが利用可能になります。ShortcutCustomizeUI.build()を実行するとPromiseが返され、そのPromiseの解決後の値として、生成されたDocumentFragmentが得られます。後は、以下のようにして設定画面の中にDocumentFragmentを埋め込むだけです。

ShortcutCustomizeUI.build().then(list => {
  document.getElementById('shortcuts').appendChild(list);
});

すると、以下のスクリーンショットのようなUIが使えるようになります。
(実際に表示されたUIのスクリーンショット)
各ショートカットにはコマンドの名前もしくは説明文がラベルとして表示され、行の右端のボタンをクリックすることで初期値に戻すこともできます。

  • このライブラリはmanifest.jsoncommandsで定義されている全てのコマンドを自動的に走査し、UIに列挙します。コマンド名を各言語に応じた翻訳で表示したい場合は、manifest.json自体の国際化のための機能を使用して下さい。
  • ShortcutCustomizeUI.build()に指定できるオプションの詳細については、リポジトリ内のREADMEファイルを参照して下さい。
  • 実際にはショートカットとしては使えないキーの組み合わせも登録できる場合がありますが、その場合、そのショートカットは当然ですが機能しません。
  • キー名の入力欄にフォーカスがある状態で「Escape」キーを押すと、ショートカットの割り当てが解除されます。(ただし、後述する理由により、割り当て解除可能なショートカットを提供するには若干の準備が必要となります。)

Firefoxの組み込みのキーボードショートカットと衝突するショートカットを設定した場合、Firefoxの機能の方が優先的に動作します。アドオン側のショートカットを優先することは、現時点ではできません(1320332 - Support overriding existing keybinding through WebExtensionsも参照して下さい)。

既定のキーボードショートカットを割り当て解除できるようにする

WebExtensionsでは通常、アドオンの既定のショートカットはmanifest.jsoncommands配下にsuggested_keyとして記述します。しかし、素直にこの方法を使って定義した既定のショートカットには、ユーザーが割り当て解除できないという問題があります*2。本ライブラリは、このWebExtensions APIの制限事項を回避して「既定のキーボードショートカットをユーザーが任意の割り当て解除する」という事を可能にするための機能を含んでいます。

この機能を使うためには、まず下準備としてmanifest.jsonの書き換えが必要です。

  "commands": {
    "_execute_browser_action": {
      "suggested_key": { "default": "F1" },
      "description": "__MSG_sidebarToggleDescription__"
    },

このようにsuggested_keyで定義していた既定のショートカットを、以下のようにdescriptionの中で半角丸括弧で囲う形で記述し直して下さい*3

  "commands": {
    "_execute_browser_action": {
      "description": "__MSG_sidebarToggleDescription__ (F1)"
    },

その上で、ShortcutCustomizeUI.jsをバックグラウンドページで読み込み、アドオンのインストール直後の1回だけShortcutCustomizeUI.setDefaultShortcuts()を実行して下さい。例えば、storage.localを使うなら以下のようにします。

(async () => {
  const SHORTCUTS_VERSION = 1;
  const configs = await browser.storage.local.get({ shortcutsVersion: 0 });
  switch (configs.shortcutsVersion) {
    case 0:
      ShortcutCustomizeUI.setDefaultShortcuts();
  }
  browser.storage.local.set({ shortcutsVersion: SHORTCUTS_VERSION });
})();

ShortcutCustomizeUI.setDefaultShortcuts()を実行すると、ライブラリがmanifest.jsondescriptionに記述されたショートカットを自動的に収集し、ショートカットの初期値として自動設定します。このようにして動的に反映されたショートカットは、browser.commands.reset()で空の状態にリセットできるため、「割り当て解除可能な既定のショートカット」として振る舞う事になります。

アドオンの更新などで後からまたショートカットを追加したという場合には、ShortcutCustomizeUI.setDefaultShortcuts()を再実行するのではなく、以下のようにして、個別のコマンドに対しShortcutCustomizeUI.setDefaultShortcut()を実行するようにして下さい。

  "commands": {
    "_execute_browser_action": {
      "description": "__MSG_sidebarToggleDescription__ (F1)"
    },
    "newCommand": {
      "description": "__MSG_newCommand__ (Ctrl+Alt+PageUp)"
    },
(async () => {
  const SHORTCUTS_VERSION = 2; // 初期化済みかどうか判定するバージョンを繰り上げる
  const configs = await browser.storage.local.get({ shortcutsVersion: 0 });
  switch (configs.shortcutsVersion) {
    case 0:
      ShortcutCustomizeUI.setDefaultShortcuts();
    case 1:
      ShortcutCustomizeUI.setDefaultShortcut('newCommand');
      ShortcutCustomizeUI.setDefaultShortcut('extraCommand');
  }
  browser.storage.local.set({ shortcutsVersion: SHORTCUTS_VERSION });
})();

改善のためのご協力のお願い

このアドオンが生成するUIにはキーボードのモディファイアキーやその他のキー名が表示されますが、キーの表示名は言語によって異なる場合があります。そのため、ライブラリ内で言語ごとの表示名を定義していますが、現状ではごく一部の言語のみの対応に留まっています。

もし他の言語のことに詳しい方がいらっしゃいましたら、キーの表示名と内部名の対応表の追加にご協力をいただければ幸いです。

まとめ

WebExetnsionsによるFirefox用アドオンに簡単にキーボードショートカット変更用のUIを追加できる軽量ライブラリであるShortcutCustomizeUI.jsについて、その使い方を解説しました。「以後確認しない」のようなチェックボックスを伴った確認ダイアログを表示するRichConfirm.jsや、メニュー風のUIを提供するMenuUI.jsと併せて、Firefox用アドオンの開発にご活用いただければ幸いです。

*1 使用できるキーの種類などの面で自由度が高いのは後者ですが、実行のためには全てのページでユーザースクリプトを実行する権限(<all_urls>)が必要な上に、コンテンツ領域にフォーカスがある時でないとイベントを認識できない、addons.mozilla.orgのページやabout:addonsなどのFirefox自体が提供するページでは動作しない、などの欠点があります。

*2 Firefox 63やFirefox 64といった将来のバージョンで修正される可能性はありますが、セキュリティアップデートのみが提供されるFirefox ESR60ではこの問題は修正されない見込みです。

*3 このような書き方をする都合上、`suggested_key`では可能なプラットフォームごとの既定のショートカット割り当ては、このライブラリではできないという制限事項があります。あしからずご了承ください。

タグ: Mozilla
2018-05-14

Unixシェルで手軽にデータを集計する (前編)

クリアコードの藤本です。

私たちの業務では、よく「データを集計する」という仕事が発生します。 例えば、最近の改修の効果を測定するために、過去ログからリクエストの成功率を測定したり、 お客様への業務報告のために、チケットシステムから直近の稼働状況を集計したりします。

もちろん、同じようなタスクが定型的に発生するようであれば、専用のスクリプトを作り込むのですが、 この種類のタスクは単発限りで結果が取れればよい、ということが少なくありません。

私(筆者)は、このようなタスクがある時は、Unixの標準ツール(とPython)を使って集計しています。 今回の記事では、具体的にどのように集計を行っているかを紹介したいと思います。

例: シェルでコマンドの実行回数を集計する

実際のタスクに適度に近い例として、「コマンドの実行履歴を集計する」というタスクを例に 集計のやり方を説明したいと思います。

bashであれば、集計対象のデータ(=コマンドの実行履歴)はhistoryで簡単に取得できます。

$ history
 ...
 1952  cd
 1953  ls
 1954  git add -p
 1955  git log
 1956  git commit --amend

ここから「自分が最もよく実行しているコマンド」を集計してみましょう。 大雑把には、左から二番目の列を取り出して、コマンドごとに件数を数えればよさそうです。
(注: ここではパイプやインラインのコマンドは無視しています)

この処理の実現の仕方にはいくつかあるのですが、筆者であれば次のように打ち込んで集計します:

$ history | awk '{print $2}' | sort | uniq -c | sort -rn | head
    345 vim
    159 python
    101 ls
     52 cd
     48 grep
     39 ll
     32 cat
     31 history
     26 git
     23 rm

実行したコマンドの中身については後ほど解説しますので、まずは出力の方をご覧ください。 左側がコマンドの出現回数で、右側が対応するコマンドの名前です(出現回数が多い順に並んでます)。 この端末では、vimが最も多く実行されていることがご覧いただけると思います。

皆さんも、試しに上のコマンドを自分の環境で実行してみると、 自分が普段どのコマンドを使ってるのかが分かって楽しいと思います。

全体構成: パイプによるプログラムの連結

まずはコマンドの全体の構成から説明します:

$ history | awk '{print $2}' | sort | uniq -c | sort -rn | head

すぐに見てとれるように、このコマンドは6つのプログラムを | 記号で連結したものです。 この縦棒記号でプログラムをつなげる仕組みをパイプ(あるいはパイプライン)と呼びます。 パイプで連結すると、前のプログラムの結果を、後のプログラムに流すことができます。

より単純なechotrというコマンドを例に仕組み説明します。 echoは入力として与えられた内容をそのまま出力するプログラムです:

$ echo aiueo 
aiueo

これをtrという「文字列を置換するコマンド」に流してみましょう:

$ echo aiueo | tr a x  # "a"を"x"に置換する
xiueo

2つのコマンドがパイプを通じて接続されているのが見て取れると思います。 もちろん、この後にさらにコマンドを連ねていくことも可能です:

$ echo aiueo | tr a x | tr o x  # さらに"o"を"x"に置換する
xiuex

同じ要領でコマンドをいくらでもつなげていくことができます。 このように何段も連結するのは現実の場面でもそう珍しいことではありません (実際、先ほどの集計コマンドでは6つのプログラムを接続しています)。

普段何気なく使うことが多いのですが、パイプはUnixの偉大な発明の一つです。

構成要素(1): awkによるテキスト処理

集計コマンドの全体像がつかめたところで、パイプラインの最初に登場するawkに注目しましょう。

このプログラムは平たく言えば「テキストを行単位で処理するツール」です。 雑多なテキストから必要なデータを抽出するのに活躍してくれるプログラムで、 今回のケースでは「コマンド履歴の2列目を取り出す」という処理に利用してます:

$ history | awk '{print $2}'
...
cd
ls
git
git
git

awkの引数の中身をあれこれいじってみると、感覚がつかめると思います。 例えば$2$1に変えると、一列目が取り出せます。

$ history | awk '{print $1}'
...
1952
1953
1954
1955
1956

紙幅の関係で省略しますが、実はawkの正体は非常に高度な機能を備えた本物のプログラミング言語です。 処理の中でループ構文や関数を使うこともでき、他の一般的なスクリプト言語に匹敵する表現力を持っています。 したがって、指示の与え方を工夫すれば、大抵の処理はawkだけで実現することができます。

実際、本記事のコマンド集計の処理も、やろうと思えばawkだけで実現することができます:

$ history | awk '{A[$2]+=1} END{PROCINFO["sorted_in"]="@val_num_desc";for(i in A) print A[i],i}'
345 vim
159 python
101 ls
52 cd
48 grep
39 ll
32 cat
...

こう話を進めると、最初からawkだけで全ての処理を済ませれば良いように思えてくるのですが、 実際にはawkだけで処理を完結させるのは稀で、最初に示したコマンド集計の例のように、 より単純なコマンドとの組み合わせで処理を実現することの方が圧倒的に多いです。

この理由は、おそらく上のコマンド集計の実装例を見れば、何となく察しがつくのではないか と思います。このawkプログラムはわずか80字に満たない短い実装ですが、 既に一目で何が行われているのかを把握できる水準を(書いた本人の筆者にとってすら)越えてきています。

もちろん、インラインで収めようとせずに、テキストエディタで整形しながら書けば、 コードの見通しは俄然よくなるのですが、そもそもコマンドラインで集計しようとしている発端が 「テキストエディタで本式のプログラムを書くのが面倒」という点にあったこと考えると、 本末転倒の感が強くなってきます。

本記事で、あくまでawkを「2列目を取り出す」という単純な処理にしか用いず、 実際の集計処理を後続のコマンドに委ねているのは、このような理由によるものです。

(後編に続きます)

タグ: Unix
2018-05-16

Active Directoryを使用していない環境で、Firefoxに任意のルート証明書を自動インポートする方法

既報の通り、Firefox 52以降のバージョンではActive Directoryのグループポリシー経由で配布された証明書を自動的にインポートできるようになっています。アドオンなどによる証明書の自動インポートができなくなったため、現時点ではFirefoxに任意のルート証明書を組み込んだ状態にするには、これが唯一の方法となっています。

ただ、Active Directoryを運用してない小規模の組織や、検証用のスタンドアロンのPCでは、何らかの方法で「Active Directoryのグループポリシー経由で証明書を配布した状態」と同じ状態にする必要があります。以下はそのための作業手順の説明となります。

背景

Windowsの証明書データベースは、実際にはレジストリ上の複数の位置にある情報が集約されて認識された物です。証明書のバイナリはレジストリ上ではBlob形式のレジストリ値として保存されています。

この事は、任意の証明書を主導でインポートした後でレジストリエディタを起動し HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates 以下の状態を見ることで分かります。

Active Directoryのグループポリシーで証明書を展開すると、証明書データベースを構成する複数のレジストリキーのうち、以下の位置のいずれかに情報が書き込まれます。

  • HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates\Root\Certificates
  • HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\SystemCertificates\Root\Certificates
  • HKEY_LOCAL_MACHINE\Software\Microsoft\EnterpriseCertificates\Root\Certificates

よって、「Active Directoryのグループポリシー経由で証明書を配布した状態」と同じ状態を作り出すためには、必要な証明書の情報を上記のキー配下に書き込めばよいと言う事になります。

準備

以上のような背景があるため、Firefoxにインポートさせたい証明書はまず一旦、Windowsの証明書データベースにインポートしておく必要があります。まだインポートされていない場合は、以下の手順で証明書をインポートしておいて下さい。

  1. 証明書ファイルをダブルクリックして、証明書のプロパティを開く。
  2. 「詳細」タブでフィールド「拇印」の値(SHA-256ではなくSHA-1)を確認し、控えておく。
    以下、拇印は49cb1e088952d5116738db438a11c5aba7a12e01と仮定する。
  3. 「全般」タブで「証明書のインストール」ボタンをクリックする。
  4. 証明書のインポートウィザードが開かれるので、以下の設定でインポートする。
    • 現在のユーザー 用
    • 「証明書を全て次のストアに配置する」で「エンタープライズの信頼」を選択

レジストリファイルの作成

レジストリエディタでインポートするための証明書ファイルは、以下の手順で作成します。

  1. 「ファイル名を指定して実行」で regedit.exe と入力し、レジストリエディタを起動する。
  2. 「編集」→「検索」で、検索する値として、当該証明書の拇印(SHA-1 Fingerprint)を入力する。
    ここでは49cb1e088952d5116738db438a11c5aba7a12e01と仮定する。
  3. 名前が上記の拇印と一致する*1キーが見つかる。 (「準備」の項の手順でインストールした場合、 HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates\trust\Certificates配下にある。)
  4. 見つかったキーを右クリックし、「エクスポート」を選択してEnterpriseCert.regなどの名前で保存する。
  5. 「準備」の項の手順でインストールした場合、3で見つかったキーをレジストリエディタ上で削除する。
  6. 4でエクスポートしたファイルをテキストエディタで開く。
    (ファイルのエンコーディングは「UTF-16LE(BOM有り)」となっている)
  7. ファイルの中に含まれる文字列HKEY_〜\拇印となっている箇所(上記の例であればHKEY_CURRENT_USER\Software\Microsoft\SystemCertificates\trust\Certificates\49CB1E088952D5116738DB438A11C5ABA7A12E01)をすべて以下の文字列に置換する。
    HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\SystemCertificates\Root\Certificates\拇印
    (「準備」の項の手順でインストールした場合、HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\SystemCertificates\Root\Certificates\49CB1E088952D5116738DB438A11C5ABA7A12E01。)
  8. 編集したファイル「EnterpriseCert.reg」を上書き保存する。

以上の手順で作成したレジストリファイル「EnterpriseCert.reg」を各クライアントPCでインポートすると、グループポリシーで証明書を配布したのと同じ状態になります。

まとめ

Windowsのレジストリを編集して、Active Directoryによるグループポリシーの配布ができない環境で同等の結果を得て、Firefoxのルート証明書自動インポート機能の動作を確認する手順をご説明しました。

*1 大文字小文字は区別されません。

タグ: Mozilla
2018-05-18

Lua用のCSSセレクターパーサーライブラリー LuaCS

Lua用の使いやすいCSSセレクターパーサーライブラリーを開発しました。これは、クリアコードが株式会社セナネットワークス様からの発注を受けて開発したライブラリーです。

LuaCS(るあっくす)といいます。MITライセンスで公開しています。

LuaCSは、CSSセレクターをXPathに変換する機能を提供しています。 また、XMLuaと連携して、XML/HTMLのDOM内のノードをCSSセレクターで検索できます。

インストール方法

ライブラリーは、LuaRocksで公開しており、luarocksコマンドで簡単にインストールできます。

例えば、Debian GNU/Linuxでは以下のようにインストールします。

% sudo luarocks install luacs

Debian GNU/Linux以外のOSでのインストールは、LuaCS - インストールを参照してください。

LuaCSは、Debian GNU/Linuxの他に、Ubuntu、CentOS、macOSに対応しています。

主な機能

LuaCSの主な機能を紹介します。

LuaCSを使うとLuaで以下のことができます。

CSSセレクターをXPathへ変換する

LuaCSを使って、簡単にCSSセレクターをXPathへ変換できます。

具体的には、to_xpathsという関数を使って以下のように変換します。

local luacs = require("luacs")

-- CSSセレクターをXPathに変換
local xpaths = luacs.to_xpaths("*, .class, #id")

for _, xpath in ipairs(xpaths) do
  print(xpath)
-- /descendant::*
-- /descendant::*[@class][contains(concat(' ', normalize-space(@class), ' '), ' class ')]
-- /descendant::*[@id='id' or @name='id']
end

上記のように、to_xpathの引数には、,区切りで複数のCSSセレクターを指定できます。

XMLuaと連携して、XML/HTMLのDOM内のノードをCSSセレクターを使って検索する。

Lua用HTML・XML処理ライブラリー XMLua は、version 1.0.4 からCSSセレクターを用いたノードの検索をサポートしています。 XMLuaのCSSセレクターを用いた検索機能は、LuaCSを使って実現しています。

CSSセレクターを用いた検索は、以下のように行います。

検索条件にマッチしたノードは、Luaのテーブルとして取得できますので、[]を用いたアクセスや#を用いて、検索条件にマッチしたノード数を取得できます。

local xmlua = require("xmlua")

local xml = [[
<root>
  <sub1 class="A" id="CB"/>
  <sub1 class="B"/>
  <sub1 class="C">
    <sub1 class="B" id="CB"/>
  </sub1>
  <sub2 class="B"/>
  <sub1 class="D"/>
</root>
]]

local document = xmlua.XML.parse(xml)

-- class="B" または、id="CB"の要素をすべて検索します。
local all_classes = document:css_select(".B, #CB")

-- "#"を使ってマッチしたノードの数を出力できます。
print(#all_classes) -- -> 4

-- "[]"を使って、N番目のノードにアクセスできます。
print(all_classes[1]:to_xml()) -- -> <sub1 class="B"/>
print(all_classes[2]:to_xml()) -- -> <sub1 class="B" id="CB"/>
print(all_classes[3]:to_xml()) -- -> <sub2 class="B"/>
print(all_classes[4]:to_xml()) -- -> <sub1 class="A" id="CB"/>

おわりに

LuaCSの主な機能を紹介しました。より詳しい内容については、以下のドキュメントも参照してください。

LuaCS - リファレンス

LuaCS - チュートリアル

このライブラリーは、XMLuaと同様株式会社セナネットワークス様からの依頼を受けて開発した受託開発の成果物です。

成果物をフリーソフトウェアとして公開すると、様々なユーザーがライブラリーを使うことによって、いままで気が付かなかったバグを発見できたり、ユーザーからの要望によって、当初想定していなかった、便利な新機能を実装するきっかけとなったり、様々なメリットがあます。

このように成果物の公開によって、ライブラリーの品質も高まるので、お客さんにとっても成果物を公開するメリットがあります。

ご依頼主の株式会社セナネットワークス様には、上記のようなメリットにご理解をいただき、成果を公開できました。ありがとうございます!

2018-05-23

DebianパッケージでMesonに移行するプロジェクトに対応するには

はじめに

Mesonはソフトウェアをビルドする、ビルドシステムの1つです。 GNOME関連だと、すでに多くのモジュールがMesonに対応しています。

今回は、アップストリームがビルドシステムをMesonに移行した場合にどのように対応すればいいかを紹介します。

libhinawaの場合

libhinawaの場合、これまではビルドシステムとしてAutotoolsを採用していました。 1.0のリリースにともない、Mesonに移行する話があったため、実際にどうやればよいかを調べてみました。 アップストリーム側のMeson対応自体はトピックブランチも用意されていたので、それをもとに試してみました。

% git clone https://github.com/takaswie/libhinawa.git libhinawa.meson
% cd libhinawa.meson
% git checkout -b meson-build origin/topic/meson-build

上記トピックブランチで用意されたmeson.buildmeson_options.txtにあわせてDebianパッケージ側で修正が必要なのは以下の2つのファイルです。

  • debian/rules
  • debian/control

debian/rulesを修正する

変更前のdebian/rulesは以下のようになっていました。(必要な箇所のみ抜粋)

%:
        dh $@ --with gir

これをMesonに対応させるためには、次のように明示的にビルドシステムの指定を追加します。

%:
        dh $@ --with gir --buildsystem=meson

ビルドシステムはこのほかにもいくつかサポートされているものがあります。 どんなビルドシステムがサポートされているかは、次のコマンドを実行することで確認できます。

% dh_auto_configure --list
autoconf             GNU Autoconf (configure)
perl_build           Perl Module::Build (Build.PL)
perl_makemaker       Perl ExtUtils::MakeMaker (Makefile.PL)
makefile             simple Makefile
python_distutils     Python Distutils (setup.py) [DEPRECATED]
cmake+makefile       CMake (CMakeLists.txt) combined with simple Makefile
cmake+ninja          CMake (CMakeLists.txt) combined with Ninja (build.ninja)
ant                  Ant (build.xml)
qmake                qmake (*.pro)
qmake_qt4            qmake for QT 4 (*.pro)
meson+ninja          Meson (meson.build) combined with Ninja (build.ninja)
ninja                Ninja (build.ninja)
kde+makefile         CMake with KDE 4 flags combined with simple Makefile [3rd party]
kde+ninja            CMake with KDE 4 flags combined with Ninja (build.ninja) [3rd party]
kf5+makefile         CMake with KDE Frameworks 5 flags combined with simple Makefile [3rd party]
kf5+ninja            CMake with KDE Frameworks 5 flags combined with Ninja (build.ninja) [3rd party]

Auto-selected: autoconf

厳密には--buildsystem=meson+ninjaが正しいのですが、歴史的経緯から--buildsystem=mesonだけでもよいようです。

debian/controlを修正する

ビルドシステムをMesonに移行するので、パッケージの依存関係も修正が必要です。

debian/controlのAutotools依存の部分を書き換えればよいです。

diff -u libhinawa/debian/control libhinawa.meson/debian/control
--- libhinawa/debian/control    2018-04-21 17:47:20.539799697 +0900
+++ libhinawa.meson/debian/control      2018-05-25 17:07:55.979775347 +0900
@@ -4,7 +4,7 @@
 Maintainer: Takashi Sakamoto <o-takashi@sakamocchi.jp>
 Uploaders: Kentaro Hayashi <hayashi@clear-code.com>
 Build-Depends: debhelper (>= 11),
-    automake (>= 1.10), autoconf (>= 2.62), libtool (>= 2.2.6),
+    meson,
     libglib2.0-dev (>= 2.32.0),
     gtk-doc-tools (>= 1.18-2),
     gobject-introspection (>= 1.32.1),

Mesonでビルドしてみる

修正ができたところで、実際にMesonを使ってビルドできるか試してみます。

% debuild -us -uc -nc
dpkg-buildpackage -rfakeroot -us -uc -ui -nc
dpkg-buildpackage: info: source package libhinawa
dpkg-buildpackage: info: source version 1.0.0-1
dpkg-buildpackage: info: source distribution unstable
dpkg-buildpackage: info: source changed by Kentaro Hayashi <hayashi@clear-code.com>
 dpkg-source --before-build libhinawa.meson
dpkg-buildpackage: info: host architecture amd64
  debian/rules build
dh build --with gir --buildsystem=meson
   dh_update_autotools_config -O--buildsystem=meson
   dh_autoreconf -O--buildsystem=meson
dh_autoreconf: Only runs once, see dh-autoreconf(7)
   dh_auto_configure -O--buildsystem=meson
        cd obj-x86_64-linux-gnu && LC_ALL=C.UTF-8 meson .. --wrap-mode=nodownload --buildtype=plain --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=lib/x86_64-linux-gnu --libexecdir=lib/x86_64-linux-gnu
The Meson build system
Version: 0.46.1
(長いので省略)

期待通りにビルドシステムにMesonが使われ、パッケージがビルドできるようになりました。

まとめ

今回は、アップストリームがビルドシステムをMesonに移行した場合にDebianパッケージ側でどのように対応すればいいかを紹介しました。 ビルドシステムが変わったときにどうすればいいかの参考にしてみてください。

2018-05-25

Gecko Embedded ESR60

はじめに

これまでにも何度か紹介してきましたが、クリアコードではGecko(Firefox)を組み込み機器向けに移植する取り組みを行っています。

当プロジェクトでは移植コストを少しでも低減するために、Firefoxの延長サポート版(ESR)のみを対象としています。これまではESR45やESR52をベースにハードウェアアクセラレーションに対応させるための作業を行ってきました。 現在はESR60に対応し、そのバグを修正する作業を進めています。

今回は、この作業の現在のステータスを紹介します。詳細なビルド方法については、Gecko Embedded 次期ESR対応 を参照してください。

現在のステータス

現在はFirefox ESR60の開発を進めています。ビルドは通るようになり、ソフトウェアレンダリングでの描画もある程度安定して動作するようになっています。Firefox 60からはWayland対応のコードも本体に入っているため、ソフトウェアレンダリングであればほぼ無修正で動作させることができています。 また、60ESRには入りませんでしたが、当プロジェクトが作成したEGLおよびOpenMAX対応のパッチも無事Firefox本体に取り込まれています。

ESR52で実現出来ていたハードウェア対応の移植作業については、2018年5月30日現在、以下のような状況です。

  • レイヤーアクセラレーション: 移植済み(RZ/G1M、R-Car M3、Raspberry Pi3 Model Bで検証)
  • OpenMAX(H.264デコード): 移植済み(RZ/G1Mで検証)
  • WebGL: 移植済み(R-Car M3で動作)
  • WebRTC: レイヤーアクセラレーションとの組み合わせでは動作せず(調査中)
  • Canvas 2D Contextのアクセラレーション: e10sオフでは動作

また、ESR52ではなかった要素として、Rustで書かれたコードが追加されてきている点が挙げられます。細かく動作検証はできていませんが、少なくともStylo(Quantum CSS)は実機(Renesas RZ/G1M)で動作することを確認できています。

前回からの改善点は以下の通りです。

  • EGL有効化時に表示されるUIと操作するときに反応する座標がずれる不具合が解消した
  • UIのタブのドラッグ&ドロップが動作するようになった
  • コピー&ペーストが動作するようになった
  • WebGLがR-Car M3で動作することを確認

現状では、以下の制限があります。

  • 動画を再生&一旦停止し、別の動画を再生した時にサウンドデバイスが解放されず、音が出力されない
  • SoCのGPUがOpenGL ES 2.0のプロファイルを持ちrobustness拡張をサポートしない場合、WebGLのコンテキストが不完全となるか、コンテキスト作成に失敗する
  • Yocto 2.4ベースのBSPではStyloのビルドが確認できていない
  • Renesas RZ/G1MのPowerVR SGX 544MPを使用する場合、コンポジターでハードウェア支援を有効にするとウィンドウリサイズ時に高確率でSEGVすることがある
  • e10s有効化時にEGLを有効化するとContentプロセスがSEGVする

動作確認を行ったハードウェア

現時点ではRenesas RZ/G1M、R-Car M3、また、コミュニティサポートのレベルですが、StyloのビルドサポートなしでRaspberry Pi3 Model Bにも移植しました。

まとめ

GeckoEmbeddedプロジェクトのESR60の状況とビルド方法について紹介しました。ESR60対応がひと段落し、対象ボードを拡充する対応は少しづつ進んでいるものの、まだまだ手が足りていない状況です。興味を持たれた方は、ぜひ当プロジェクトに参加して頂ければ幸いです。

2018-05-30

«前月 最新記事 翌月»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|