高速検索 the_silver_searcher を使ってみる

こんにちは、masm11 です。 たまには新しいツールでも導入して快適になってみましょう。

今回ご紹介するのは、高速検索ツール the_silver_searcher です。

検索の仕方の変遷

以前は grep を使ってましたよね。

grep foo *.rb

これだとカレントディレクトリしか探してくれないので、

grep foo *.rb */*.rb

なんてしてみたり、もしくは grep に -r オプションができたので

grep -r foo .

ってのもありかもしれません。

ずっと私は find, xargs, grep を使っていました。

find . -name \*.rb -print0 | xargs -0 grep foo

こんなのですね。この程度ならさらさらと打てます。 いつも同じパターンなので。

しかし、遅いのです。もっとズババッッ! と検索して欲しいです。

the_silver_searcher とは

そこで、the_silver_searcher の登場です。速いです! 速さの秘訣を本家 github サイトから超訳すると、

  • pthread を使って並列処理している
  • バッファに読み込まず mmap() を使っている
  • Boyer-Moore の検索アルゴリズムを使っている
  • 正規表現の検索には JIT コンパイラを使っている
  • 同じ正規表現を使う時には正規表現コンパイラのキャッシュが効いている
  • .gitignore の処理も配列とバイナリサーチを駆使

さて、ではまずはインストールしてみます。

macOS の場合は Homebrew が使えます。Homebrew がインストールされているなら、

brew install the_silver_searcher

これだけです。

CentOS の場合は、

sudo yum install the_silver_searcher 

ArchLinux の場合は、

sudo pacman -S the_silver_searcher 

です。

では使ってみましょう。

the_silver_searcher というのは、ソフトウェアの名前です。 これが即ちコマンド名なわけではありません。コマンド名は ag です。 silver → 銀 → ag ですね。

ざっと実行してみた感じ、↓こんな出力です。

luna:emacs % ag pgtk_menu_show
src/pgtkterm.indent
4793:  terminal->menu_show_hook = pgtk_menu_show;

src/pgtkterm.c
4650:  terminal->menu_show_hook = pgtk_menu_show;

src/menu.h
63:extern Lisp_Object pgtk_menu_show (struct frame *, int, int, int,

src/pgtkmenu.c
619:pgtk_menu_show (struct frame *f, int x, int y, int menuflags,
luna:emacs % 

実際には色が付いていてそこそこ見やすくなっています。

f:id:masm11:20200817172509p:plain

さて、検索時間を比べてみましょう。一体どのくらい速いのでしょうか?

まずは find, xargs, grep でやってみます。 できるだけキャッシュに載せるため、連続で実行しています。

luna:emacs % for i in `seq 10`; do time bash -c '(find . -type f -print0 | xargs -0 grep pgtk_menu_show) > /dev/null 2>&1'; sleep 1; done
bash -c   0.98s user 0.70s system 51% cpu 3.259 total
bash -c   1.39s user 1.03s system 47% cpu 5.137 total
bash -c   1.27s user 1.13s system 46% cpu 5.183 total
bash -c   1.26s user 1.18s system 47% cpu 5.148 total
bash -c   1.30s user 1.17s system 47% cpu 5.197 total
bash -c   1.27s user 1.01s system 44% cpu 5.051 total
bash -c   1.39s user 1.09s system 47% cpu 5.165 total
bash -c   1.33s user 1.16s system 47% cpu 5.239 total
bash -c   1.10s user 1.02s system 45% cpu 4.624 total
bash -c   0.92s user 0.96s system 47% cpu 3.942 total
luna:emacs % 

1回5秒程かかっています。次に ag を使って検索してみます。

luna:emacs % for i in `seq 10`; do time ag pgtk_menu_show > /dev/null; sleep 1; done
ag pgtk_menu_show > /dev/null  0.10s user 0.16s system 361% cpu 0.071 total
ag pgtk_menu_show > /dev/null  0.14s user 0.14s system 406% cpu 0.067 total
ag pgtk_menu_show > /dev/null  0.11s user 0.16s system 407% cpu 0.065 total
ag pgtk_menu_show > /dev/null  0.13s user 0.14s system 401% cpu 0.066 total
ag pgtk_menu_show > /dev/null  0.14s user 0.13s system 400% cpu 0.067 total
ag pgtk_menu_show > /dev/null  0.11s user 0.13s system 385% cpu 0.061 total
ag pgtk_menu_show > /dev/null  0.11s user 0.15s system 401% cpu 0.065 total
ag pgtk_menu_show > /dev/null  0.10s user 0.16s system 401% cpu 0.066 total
ag pgtk_menu_show > /dev/null  0.08s user 0.20s system 362% cpu 0.077 total
ag pgtk_menu_show > /dev/null  0.12s user 0.16s system 400% cpu 0.068 total
luna:emacs % 

1回 0.1 秒未満!? 素晴らしいスピードです。

the_silver_searcher を Emacs で使う

dumb-jump

Emacs でタグジャンプと言えば、TAGS ファイルでしょうか。 私はほとんどお世話になったことがありません。 ずっと find, xargs, grep でやってました。

上で見た通り、ag がこれだけのスピードで返答を返せるなら、 TAGS なんてなくても、その場で力任せに検索してやればいいですよね? そのためのパッケージが Emacs にあります。dumb-jump といいます (dumb-jump は grep にも対応しています)。

このパッケージは主に「このメソッドの実体はどこにあるのかな~」 と探すためにあるようです。

  1. M-x package-list-packages で dumb-jump を探してインストールします。
  2. ついでに ivy, posframe, ivy-posframe も使うことにするのでインストールします。
  3. ~/.emacs (または ~/.emacs.d/init.el ですかね?) に以下のように設定して Emacs を再起動します。 ivy と ivy-posframe の設定もしてるので長いですが、dumb-jump の 設定自体は最後の段落のみです。
(require 'ivy)
(ivy-mode 1)
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)
(setq ivy-height 15)
(setq ivy-extra-directories nil)
(setq ivy-re-builders-alist
      '((t . ivy--regex-plus)))
(define-key ivy-minibuffer-map "\C-t" 'ivy-scroll-down-command)

(require 'ivy-posframe)
(setq ivy-posframe-display-functions-alist
      '((t . ivy-posframe-display-at-frame-center)))
(ivy-posframe-mode 1)

(require 'dumb-jump)
(setq dumb-jump-mode t)
(setq dumb-jump-selector 'ivy)
(setq dumb-jump-use-visible-window nil)

さて、何らかのソースコードを開き、メソッドを呼び出しているところに テキストカーソルを合わせ、おもむろに M-C-g を押してみてください。 1秒かからないくらいで、メソッド定義位置の候補が childframe に 表示されたと思います。「これが定義のはず」と思う行を選択して Enter を 押せば、その行にジャンプします。

「ジャンプ前の行どこだっけ?」と思ったら、M-C-p で戻れます。

また、M-C-q を使うと、そのメソッドを使っている箇所がいくつか childframe に表示されます。メソッドが他の箇所で具体的にどう呼ばれているかを見たい 時に便利... なのでしょうか、これは便利さがまだよく解りません。

そして、言語によっては、カーソルのある位置からメソッド名を うまく取り出せないことがあるようです。 そういう時は、メソッド名を範囲指定してから M-C-g を押すと、 うまく検索してくれます。

ag

dumb-jump はタグジャンプしくれますが、もっと単純に grep みたいに 検索して欲しいことがあります。つまり M-x grep の代わりです。

その名も ag というパッケージがあります。

  1. M-x package-list-packages で ag を探してインストールします。
  2. ~/.emacs に以下のように設定して Emacs を再起動します。
(eval-after-load 'ag
  (lambda ()
    (setq ag-arguments '("--nobreak" "--smart-case" "--stats"))
    (fset 'masm11:ag (symbol-function 'ag))
    (fset 'masm11:ag-project (symbol-function 'ag-project))
    (defun ag (arg)
      (interactive "P")
      (if arg
          (masm11:ag (ag/read-from-minibuffer "Search string")
                     (read-directory-name "Directory: "))
        (masm11:ag-project (ag/read-from-minibuffer "Search string"))))
    (define-key ag-mode-map "n" 'next-error-no-select)
    (define-key ag-mode-map "p" 'previous-error-no-select)
    ))

本来 M-x ag が文字列とディレクトリを指定するバージョンで、 M-x ag-project が文字列だけを指定するバージョンです。 M-x ag-project の方はプロジェクト配下のディレクトリ全てにわたって 検索してくれます。

が、どちらかというと、M-x ag-project の方をよく使うと思うので、 そちらを M-x ag として使うようにしました。元々の M-x agC-u M-x ag で使えるようにしてあります。

そして、結果を表示しているバッファでは、n, p で次のヒットと前のヒットを 移動できますが、M-x grep のように該当ファイルの該当行を表示しては くれません。Enter を押せば表示してくれるのですが。そこで、keymap をいじって M-x grep と同様の動作になるようにしてみました。

あと、ag-arguments については、元々は、マッチを含むファイルごとに 空行が挿入されているのですが、見づらいので入れないようにしました。 元々しっかり色が付いているので、空行がなくても全然問題はありません。

おまけ

ag の出力は上記の通り、デフォルトではツールに食わせるのには向いていません。 しかし、実はそれは端末に出力する場合のみで、パイプに出力させると、 以下のようにツール向きの出力になります。

luna:emacs % ag pgtk_menu_show | cat
src/pgtkterm.indent:4793:  terminal->menu_show_hook = pgtk_menu_show;
src/pgtkterm.c:4650:  terminal->menu_show_hook = pgtk_menu_show;
src/menu.h:63:extern Lisp_Object pgtk_menu_show (struct frame *, int, int, int,
src/pgtkmenu.c:619:pgtk_menu_show (struct frame *f, int x, int y, int menuflags,
luna:emacs % 

また、ag は .gitignore を参照します。.gitignore に書かれているファイルは検索対象外です。 .gitignore に書かれているファイルも対象にするには、-t などを指定するのが良いでしょう。

(いまさらですが、実は先述のスピード差は、.gitignore に書いてあるファイルを対象外にしてるから、というのが最も大きいです)

まとめ

ag はとても良さげなものだと思っています。 ただ、ivy, posframe の方がまだまだ粗削りで、使いにくいです。 そのあたりも含めて、今後 ag に慣れていきたいな、と思います。

ではまた!!

tar で固める際に進捗を知る

こんにちは。masm11 です。

大きなディレクトリを tar で .tar.gz に固めることってありますか? 時々ありますよね。 最近は zip の方が多いのでしょうか? 私は tar を使っています。例えば以下のようにします。

tar zcf /bak/backup.tar.gz dir

しかし、大きなディレクトリを .tar.gz にすると時間がかかるので、進捗を知りたくなります。

今回はその方法を紹介したいと思います。

まずは普通に

tar に v を付けると、ファイル名を出力してくれます。

tar zcvf /bak/backup.tar.gz dir

ですが、この場合、ファイル名とエラーメッセージが両方端末に出力されるので、 エラーの確認が難しいです。

ファイル名を別ファイルに保存する

tar zcvf /bak/backup.tar.gz dir > log

こうすると、 log にファイル名が出力されていきます。エラーメッセージは端末に出力されます。

log は別端末で

tail -f log

とでもしておけば、確認できますね。

別端末に送り込む

ファイルに出力するのが嫌な場合、別端末に直接送り込むこともできます。

端末を2枚開いて、それぞれで

tty

というコマンドを実行します。端末の ID のようなものが出力されます。 ここでは、/dev/pts/0, /dev/pts/1 だとします。

/dev/pts/0

tar zcvf /bak/backup.tar.gz dir > /dev/pts/1

と実行すると、/dev/pts/1 の方にファイル名が出力されます。エラーメッセージは /dev/pts/0 の方に出力されます。

各ファイルのサイズも見たい場合

例えば

tar ztvf /bak/backup.tar.gz

を実行すると、backup.tar.gz の中にあるファイルの、ファイル名やサイズ等が出力されます。

固めている間に見たければ、別端末でこのコマンドを何度も実行すれば、そのたびにファイル名やサイズ等が出力されますが、 backup.tar.gz は大きいので、一度見た前の方の情報は不要です。できれば、tar zcvf の時のように順次出力して欲しいです。

そこで、tail -f を使う方法を考えました。

/dev/pts/1:

echo -n '' > /bak/backup.tar.gz
tail -f /bak/backup.tar.gz | tar ztvf -

/dev/pts/0:

tar zcf /bak/backup.tar.gz dir

tar zcf で backup.tar.gz を作っていきます。backup.tar.gz が大きくなったら大きくなった部分だけ tail -f で読み取り、 tar ztvf でファイル名やサイズ等を出力しています。

ただ注意として、既に大きくなった backup.tar.gz がある場合、tail -f は後ろの方しか出力してくれないので、zcat が 「ファイル形式がおかしい」とエラーを吐きます。なので、tail -f は先に実行しておく必要があるのですが、 ファイルがなければ tail -f がエラーになりますので、最初に echo -n で空ファイルを作っています。 touch でもファイルを作れますが、もしファイルがあった場合、タイムスタンプが変わるだけになってしまうので、 明示的に空ファイルにするために echo -n にしています。

結果は以下のような感じになります。

f:id:masm11:20200715123320p:plain
実行中画面サンプル

まとめ

tar zcf で大きなディレクトリを固めている際に進捗を知る方法を紹介しました。

いろいろな方法がありますね。UNIX/Linux ではいろいろな方法があって、好みの方法を選べるところが私は好きです。

ではまた!

dovecot が起動してない?

https://upload.wikimedia.org/wikipedia/commons/3/37/Dovecot-logo.png

どうも id:kizashi1122 です。

弊社が開発・運営している Re:lation というサービスの中のサーバではないのですが、とある用途で IMAP のサーバをAWSのEC2上に立てていました。ソフトウェアとしては dovecot を使っています。

Dovecot

さて、社内の利用者より「つながらないんですけど」と連絡がありました。

んなアホなと思い、みてみると確かに IMAP の接続に失敗する。認証に失敗ではなく接続に失敗する。

$ ps -ef | grep dovecot

をすると、プロセスがあがってません。 ps auxw を使ってない理由は特にないありません。昔 Solaris を使っていた手癖がまだ残ってるだけです・・・。

それはさておき。

上がってないなら上げればよいということで起動させようとしました。

[root@ip-172-31-XX-XX conf.d]# /etc/init.d/dovecot start
Starting Dovecot Imap: Error: service(pop3-login): listen(*, 995) failed: Address already in use
Error: service(imap-login): listen(*, 143) failed: Address already in use
Error: service(imap-login): listen(*, 993) failed: Address already in use
Fatal: Failed to start listeners
                                                           [FAILED]
[root@ip-172-31-XX-XX conf.d]#

誰かがポートを使ってる? んなアホな。

lsof で確かめます。

[root@ip-172-31-XX-XX conf.d]# /usr/sbin/lsof -i :993
[root@ip-172-31-XX-XX conf.d]# /usr/sbin/lsof -i :995
[root@ip-172-31-XX-XX conf.d]# /usr/sbin/lsof -i :143

ないんかい。

念の為、 netstat -tulpn でもみてみますが同ポートは誰もLISTENしてません。

困った。

困ったときの Google 先生。 以下のサイトがみつかりました。日付も近い。

stackoverflow.com

Hi it looks like you are using AWS as I am. I recently updated via Yum as well. I noticed that a new package named 'portreserve' was also installed. I killed that process, left the /etc/dovecot/dovecot.conf as it was before and then started Dovecot successfully. I was also immediately able to reconnect my mail clients connection. I hope that helps you.

I also restarted the portreserve program since it seems useful to limit port access.

まとめると、「最近 yum でアップデートしたら portreserve なるパッケージがインストールされてた。このプロセスを kill して dovecot を起動したらうまくいった」とのこと。

確かに、最近 yum でセキュリティアップデートがあったので yum update -y したばかりでした。その後再起動して放置してました。まさか dovecot が立ち上がってないとは思わず・・・。

実際に、このとおりにすると無事 dovecot が再起動しました。

ただ次にOSを再起動した際に同じことが起こるのはイヤです。

/etc/portreserve/ というディレクトリに dovecot というファイルがあります。

中身は

imap/tcp
imaps/tcp
pop3/tcp
pop3s/tcp
sieve/tcp

というような感じ。もうこいつが原因だろうということでこのファイルは削除しました。

ところで、この portreserve というサービスは何者なんでしょう? その名の通り、dovecot のために上記ポートを予約しておいてくれたのなら、なんで dovecot が立ち上がらなかったんだ?

謎が多いです。

今後は簡単に確認できるように、簡単な Perl スクリプトを作りました。

#!/usr/bin/env perl

use v5.16;
use Mail::IMAPClient;

my $imap_host = $ARGV[0] or die $!;
my $user      = $ARGV[1] or die $!;
my $pass      = $ARGV[2] or die $!;

my $imap = Mail::IMAPClient->new(
    Server   => $imap_host,
    User     => $user,
    Password => $pass,
    Ssl      => 0,
    Uid      => 1,
);

if ($imap) {
    say "AUTH OK";
} else {
    say "AUTH NG";
}

割り算の余りは?

こんにちは、masm11 です。

突然ですが、今回は、負の整数を正の整数で割った時の余りは 0 以上なのか 0 以下なのか、 という話を書きたいと思います。

具体的には、-22 % 3 はいくつなのか、というお話です。

実は、言語によって違うのです…

2 になるものたち

Ruby

Ruby は余りが 2 になります。

仕様は以下のページにあります。

https://docs.ruby-lang.org/ja/latest/method/Numeric/i/modulo.html

また、以下のページを見ると、Ruby 1.8.7 の時には既に明確に定義されていたようですね。

https://docs.ruby-lang.org/ja/1.8.7/class/Numeric.html#I_MODULO

実際に試してみました。

luna:~ % irb
irb(main):001:0> -22 % 3
=> 2
irb(main):002:0> 

Python

Python 3 は、以下の表の下の注釈 1. に記載がありました。

https://docs.python.org/ja/3/library/stdtypes.html#typesnumeric

結果(商)が負の無限大の方向に丸められるということは、余りは 0 以上です。

Python 2.7 でも、以下のページの表の下の注釈 1. に同様の記載がありました。

https://docs.python.org/ja/2.7/library/stdtypes.html#numeric-types-int-float-long-complex

Ruby と同様に実際に試してみました。

luna:~ % python
Python 3.8.2 (default, Apr  8 2020, 14:31:25) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> -22 % 3
2
>>>

-1 になるものたち

Java

Java では余りが -1 になります。

以下のページの floorDiv メソッドに説明がありました。

https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Math.html#floorDiv-int-int-

/ で普通に割り算すると、0 に向かって丸められるようです。 ということは余りは -1 以下ですね。

そして floorDiv メソッドを使った場合は Ruby や Python と同じ丸め方になるようです。従って floorMod メソッドを使うと余りは 2 ですね。 更に、このメソッドには「導入されたバージョン: 1.8」と記載があり、Java 8 以降にしかないようです。

Java 7 については、以下に記載がありました。

https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.17.2

Integer division rounds toward 0.

やはり 0 に向かって丸めていたようです。

実際に試してみました。

luna:~ % java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (build 1.8.0_242-b08)
OpenJDK 64-Bit Server VM (build 25.242-b08, mixed mode)
luna:~ % cat test.java
class test {
    public static void main(String[] args) {
        System.out.println(-22 % 3);
        System.out.println(Math.floorMod(-22, 3));
    }
}
luna:~ % javac test.java       
luna:~ % java -classpath . test
-1
2
luna:~ % 

C99

以下に記載がありました。

https://kikakurui.com/x3/X3010-2003-01.html の 6.5.5

整数同士の除算の場合,/演算子の結果は,代数的な商から小数部を切り捨てた値とする(87)。

(87) には以下のように書いてあります。

これは, 0 方向への切捨てとも呼ぶ。

試してみました。

luna:~ % cat test.c
#include <stdio.h>

int main(void)
{
    printf("%d\n", -22 % 3);
    return 0;
}
luna:~ % cc test.c
luna:~ % ./a.out 
-1
luna:~ % 

処理系定義のもの

C89

C99 登場以前の C は C89 と呼ばれる規格に従っていました。 C89 の規格は簡単には手に入らなさそうなので、stackoverflow.com で見つけた情報 をご紹介します。

https://ja.stackoverflow.com/questions/12649/

C89 では処理系定義だったようです。つまり、結果がコンパイラや CPU に依存していた、ということです。

そんな処理系を持っていないので、残念ながら実際に試すことはできませんでした。

まとめ

C89 のコンパイラを使っていた時、ふと、余りが負であることに気付き、 私は衝撃を受けました。 それからずーっと気になっていて、今回ようやく各言語の状況をまとめることが できました。

昔はコスト的に 0 以下にすることを選んだ CPU が多く、C ではそれがそのまま 結果として現れているようです。しかし現在は CPU の処理能力も向上し、 少しくらい処理が増えても問題ないため、現代的な言語では 0 以上になっている のでしょう。

Java について言うと、私は Java は CPU 能力が潤沢にある環境で使うものだと 思っているので、そういう意味では意外な結果でした。

ではまた!

Gmail API(Google OAuth) 利用承認取得記 - 完結編

こんにちは。Tedです。

いよいよ今回でGmail API利用にかかるGoogleからの承認の取得記のラストです。

これまでの記事はこちら。

blog.ingage.jp

blog.ingage.jp

前回までで、Googleでの審査は一通り完了しました。いよいよセキュリティ評価です。

セキュリティ診断企業選び

https://support.google.com/cloud/answer/9110914 にあるように、この承認のためには第三者機関によるセキュリティ評価が必要(the system must undergo an independent (3P) security assessment)となります。また、この企業はどこでもよいわけではありません。Googleが指定する3社(すべて米国企業)から選ぶ必要があります。そしてその費用は、1万5千ドル〜7万5千ドル(約160万円~800万円)またはそれ以上かかります。

私たちの場合、このセキュリティ評価に入る時点で2019年の12月に入っていました。Google提示の3社の内、1社は多忙で年内は受け付け終了とありました。できれば年内に終わらせたかった*1ので、残りの2社から見積もりを取得することにしました。見積もりにあたり、Re:lationシステムの概要など必要な情報を提供します。これらのやりとりもすべて英語で行います。

2社からの回答は内容はほぼ同じ(当たり前)ながら、最初に出された費用は100万円ほど差がありました。ですが話を進めていく上でほとんど同じような額となりました。その見積額は約400万円でした。

両社ともしっかりした会社だったので、選ぶのには苦労しました。最終的には、回答が早く、納期も短かったB社に決めました。(とはいえ、ホリデーシーズンのためか結果的にテスト開始・終了は大幅にずれましたが)

セキュリティ評価で感じたこと

セキュリティ評価は下記のように進められました。

  1. キックオフミーティング(Web会議)

  2. B社によるセキュリティ評価

  3. 評価結果を元にレポートとその説明(Web会議)

  4. 指摘事項の修正とその内容の連絡

  5. B社での修正内容の確認

  6. 最終診断結果のレポートとその説明(Web会議)

B社から上がってきた診断レポートには、いくつか修正すべき点も指摘されていました。このレポートには私たちは大変満足しています。中には、Re:lationの仕様を十分に理解していないと指摘できないような内容も含まれていたためです。また、これまでの他社による診断では発見されなかったことも指摘に上がっていました。

はれてGoogleからの承認を得る

B社からの最終レポートをGoogleに送信すると、その翌日にはGoogleからの承認が下りました。すでに時は2020年2月も後半になっていました。Googleに最初に申請をしてから、実に4ヶ月以上・Googleとのやりとりは122回かかりました。

あらためて、今回の承認取得のポイントを下記に記したいと思います。

  • Google Cloud Consoleでの申請内容は別途保存しておきましょう。審査期間は限られており、期限を過ぎると再申請が必要となります。そのためもし再申請が必要となった際に重宝します。*2

  • 英語力は必要です。

  • 提出資料作成のため、英作文能力も必要です。

  • セキュリティ診断企業とのWeb会議のために英会話力も必要です。

  • セキュリティ診断にはまとまった費用が必要ですし、Googleが指定する企業を使う必要があります。予算の確保を前もってしておくとよいかと思います。

  • 基本的にGoogleは1-2日後には返事をくれます。

  • ただしそうでないときもあります。そんなときはフォローメールを送りましょう。*3

  • GoogleはWeb会議には応じません。コミュニケーションは必ずメールに限られます。英文での表現力・説明力はある程度必要になります。

122回のやりとりの中には、ここでは書き切れないほどのイベントが発生したのですが、ざっとこのようにまとめてみました。元々はこの3倍はあったボリュームをここまでまとめてくれたウチのCTOに感謝です。

もしこれがこれからGoogle OAuthを取得しようと思っている企業に有益となれば幸いです。質問があれば気軽にどうぞ。コメントやツイートなどwelcomeです。

*1:私たちの場合、このGoogleへの申請が12月31日で期限切れとなる予定でした。

*2:実際、私たちは期限切れで再申請する必要がありました。

*3:2-3度ほどGoogleからの返信が遅れたことがありましたが、フォローメールを送るとその翌日には返信がありました。

Gmail API(Google OAuth) 利用承認取得記 - 続

こんにちは。Tedです。

今回はGmail API(Google OAuth)の承認を得るにあたって行ったこと・起こったことについて書きたいと思います。

前回の記事はこちら

blog.ingage.jp

前回はGoogleへの申請までを書きました。今回は申請でどのようなことを行ったのか、Googleからはどのような指摘があったのかを詳しく書きたいと思います。

Googleに申請

申請の依頼自体は簡単です。 Google Developer ConsoleにてOAuth同意画面から依頼を行います。

f:id:TedWada:20200508144444p:plain

f:id:TedWada:20200508144514p:plain

このように認証を依頼するための申し込み画面は日本語で表示されていましたが、私たちが入力する文章はすべて英文で行いました。確認するのはGoogle本社(米国)であり、スムーズに審査を進めてもらうには英語で書くのがよいと思ったからです。(後述の通りこの予想は正解でした)

最初の一週間でやったこと

申請してその翌日からGoogleとのやりとりがはじまりました。流れとしては確認に際してGoogleから質問や依頼があり、それを元に私たちが回答・対応していくという流れです。Googleからの回答は素早く、こらちからのメール送信後1日から2日くらいで返信が届きます。

最初の一週間でのGoogleからの依頼とその対応は下記のようなものでした。

  • Googleサービス内のユーザデータの何を使うのか、そのためにGoogle APIの何を使うのか、なぜ使うのか、何に使うのかを文書にて回答。

  • アプリケーションが Google APIをどこで使っているかについて、デモ動画を作成。

  • Googleの審査員がアクセスできるRe:lationテスト環境の提供。

  • 外部サーバにはGoogleユーザデータは送信していない旨の説明。

  • デモ動画内のメッセージはすべて英語である必要があるとのことで、すべての日本語部分を英語に変更。*1 (当初説明テロップは英語にしていたが、Re:lation画面は日本語のままで収録していた)

  • デモ動画にてブラウザのURLバーは消さない。特にプロジェクト番号が表示されるOAuthサインインページが見えるように動画を再作成。

  • Google Cloud Console内のOAuth同意画面にて、不要なクライアントIDを削除。(開発の際に利用した不要なクライアントIDが入っていた)

  • デモ動画にて、申請している利用APIが使われるアクションが何なのかを明確にするため再収録。

申請時同様、すべてのやりとりは英語で行います。メールでのやりとりだけでなく、提供する文書もすべて英文で提出しました。

対応はなかなか終わらない

Googleによる審査は「案外しっかり見ている」と感じられるものでした。 最初の一週間以降もGoogleから下記のように指摘や質問があり、都度それらへの対応を進めました。

  • デモ画面でのアクション・説明の追加と再提出。(合計3回ほど)

  • Google OAuthにて利用するデータを明記する。

  • Googleサインインブランディングに沿った表記とする。(これは推奨であり、規定の通りとするとRe:lation内の他の設定と比較してデザインが破綻すると考えたので「やらない」と回答)

  • Re:lationにて使用するドメインはインゲージが所有していることをWebサイトにて明示する。(これはサービスサイトからログインできるページにて明示)

回答しても回答しても、Googleからは新たな指摘や質問が続きました。なかなか先が見えない中で私たちも大変でしたが、Googleも同様だったのではないかと思います。Googleからの返信の中には、すでにこちらから連絡済みのことを重複して聞いてくることも何度かあったくらいです。

Googleでの確認は終了。そして次は

上記の対応でおよそ1ヶ月が過ぎました。

Googleでの確認は一通り終わり、次のステップである第三者機関によるセキュリティ評価診断を受けるフェーズとなりました。

ここでもいくつかポイントがありました。 それについては次回に書きたいと思います。

*1:翻訳はGoogle翻訳によるウェブサイト翻訳を利用しました。

Gmail API(Google OAuth)利用承認取得記 - 思ったより大変でした

こんにちは。Tedです。

先日メール・LINE共有クラウドRe:lationにてGoogleからGmail API利用の承認を得ました。予想していたより大変であったので、備忘録的にここに記載しておこうと思います。

Google OAuth利用の声は高まっていた

Re:lationではメールの送受信にSMTP、POP3を利用します。Gmail(ここではG Suiteも併せて単に「Gmail」と書きます)ではSMTP、POP3をRe:lationなど外部メールクライアントにて利用するためには、Gmail設定にて「安全性の低いアプリを許可する」ことが必要でした。

f:id:TedWada:20200508140632p:plain

SMTP等を使うことを一方的に「安全性が低い」と決めつけられるのは気持ちのいいものではありません。ただGoogleとしてはID、Passwordを他のシステムで保存されるようなことは極力避けたいのでしょう。Google OAuthを使ってほしいという思惑でもあると思います。実際Re:lationでもGoogle OAuth対応は以前より取り組み予定として位置づけていました。

またGoogle OAuth対応までは、下記のようなお声をいただくこともありました。

f:id:TedWada:20200508140810p:plain https://twitter.com/juners/status/716261432908603392

対応の予定はしていたものの、他の案件との兼ね合いでこれまでリリースできていなかったことを申し訳ないなと感じていました。

SASL XOAUTH2対応が必要となった

いよいよRe:lationにてGoogle OAuth(SASL XOAUTH2)対応に着手できるようになった頃、奇しくもGoogleから「Turning off less secure app access to G Suite accounts(「安全性の低いアプリ」設定を廃止するよ)との通達がありました。

G Suite Updates Blog: Turning off less secure app access to G Suite accounts

この通達では2020年6月以降「安全性の低いアプリ(LSAs)」の設定に制限を実施すること、2021年2月にはこのLSAs許可設定ができなくなることが書かれていました。*1 つまりRe:lationでのGoogle OAuth対応の期日が決められたことになります。私たちは早速開発を進めました。

開発・そしてリリース

この対応にはGmailユーザのみGmail REST APIを使う手もありましたが、他のメールサービス同様にSMTPプロトコルを使う(スコープは https://mail.google.com/)こととしました。

開発およびテストはスムーズに進んだと思います。他の案件も並行して進める中で約4週間で完了しました。

ingage.co.jp

Google OAuthできない!なぜ??

この機能、リリース当日は問題ありませんでしたが、翌日になると利用者より「Google OAuthでのログインができない」との声が寄せられるようになりました。

f:id:TedWada:20200508142327p:plain
Google OAuthできずエラーになる

理由は明快でした。OAuth可能ユーザ数の上限に達したためにそれ以降のログインが許可されなくなっていたのでした。

Google OAuthを利用可能なユーザは、最初100までと決められています。

f:id:TedWada:20200508142653p:plain

このことは理解していましたが、正式に機能をリリースしてGoogleに「連絡」さえすればこの上限は外されると勝手に思い込んでしまっていました。けれどもそれは間違いで、この制限を取り払うためにはGoogleに「審査」を依頼する必要があったのでした。

Unverified apps - Google Cloud Platform Console Help

GoogleにOAuth利用を申請

Gmail APIスコープは制限されたスコープとなっています。そのため、このスコープをOAuthにて設定するにはGoogleによる以下の検証(認証)が必要です。

  • Google’s API Services User Data Policy に従っているか
  • Additional Requirements for Specific Scopes に従っているか

また加えて、上記がGoogleにて確認された後、第三者によるセキュリティアセスメントも必要となっています。

これらはかなり本格的なものであり、承認取得までには私たちが当初予測していたよりずっと長い時間と対応が必要でした。

次回は、GoogleからのGmail API承認取得までの道のりについて書きたいと思います。

*1:注:2020年5月8日時点では、Googleによるこれらの予定は急遽延期されることとなっています。おそらく新型コロナの影響かと思われます