「ナイト系」に対するスパムフィルタを作った

## 概要
「ナイト系」のスパムを防ぐためにuBlock originとuBlacklistのスパム対策ルールに対応したレポジトリを作りました。

https://github.com/KisaragiEffective/no_knightmare

## 「ナイト系」とは？
リプライツリーに自分が運営するサイトへリダイレクトする`bnc.it`で始まるURLをぶら下げ、宣伝を行う一連のアカウント群を指すようです。始めは「ナイト」というスクリーンネームのアカウントがこの手法をとっていたことからその名前がつけられたようです。
しかし、最近の同様のスパムはほとんど「ナイト」という名前を見かけません。

### 傾向
#### ツイッター上の傾向
1万いいね以上などのいわゆる「*バズった*」[^1]ツイートのリプライ欄に現れ、`bnc.it`から始まるURL (`bnc.it`自体はbit.lyと同じ、単なるURL短縮サービスです) を貼り付けることがほとんどです。
~~通常のツイートはほとんど見られません。~~ 通常のツイートは見られますが、その殆どが情報量を大して持たないひとりごとのようなツイートです。
また、アカウントがツイートする文章は他の非スパムアカウントの文面を流用したものと考えられます。中華系のような不自然な日本語はほとんど見られません。

#### ウェブサイト上の傾向
* 「賞味期限が過ぎたネタ」を最近のことかのように取り扱っていることがあります。
* ドメイン名で検索をかけると中国語がごくまれに出現することにあります。
* ドメインをwhoisにかけると、中国の企業 (例: アリババ) が登録していることがほとんどです。

### 動機
背景には **anyelse** や **Nothing Technology Inc.** と呼ばれる会社のアドセンスプログラムが絡んでいるようです。Googleアドセンスやadf.lyに比べて破格なその値段が惹きつけられた要因と考えられます。

Nothing Technology Incのホームページから引用：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/373406/ad2ae336-2cbc-56af-e376-db2ebc156cf3.png)

## 検討した代替案
ナイト系の考察はこのぐらいにして、検討した代替案を書きます。

### CustomBlockerを使う方法
下記のツイートではCustomBlockerという外部ツールを使ってTwitter上で自動的にブロックする方法が推奨されています。
しかし、Twitterは明日2月13日から無料で使えるAPIの枠を[1月1500ツイートの読み込み](https://twitter.com/TwitterDev/status/1623467618400374784)にすると[発表している](https://twitter.com/TwitterDev/status/1623467615539859456)ので、この手法は信頼性が低くなると結論づけました。
https://twitter.com/gyokuei/status/1560296764661694466

### 地道にブロックする方法
手で地道にブロックする方法も考えられます。しかし、ナイト系と考えられているアカウントは少なくとも2000〜3000アカウント[^2] [^3] [^4] [^5] [^6] [^7] [^8]はあるようで、これらすべてのアカウントをブロックするのは網羅性および汎用性に欠けます。また、ナイト系の「中の人」は次から次へアカウントを作っていると考えられるため、この方法では新しいアカウントへの対応が後手後手になりがちです。

### この方法のメリット
* ドメインごとブロックするのでGoogle検索からの流入なども対策できる
* Twitterでアカウントをいちいちブロックしないで済む

## 構築方法
まず、Google検索で下記クエリを発行しました。
* <https://www.google.com/search?q=%22zhangmin56232931%40%E2%80%8Bgmail.com%22&filter=0>
* <https://www.google.com/search?q=%22zhangyue755486%40%E2%80%8Bgmail.com%22&filter=0>

マッチしたすべてのサイト (`t.co`や`ift.tt`、`bnc.it`についてはその完全なパス) を手作業でuBlocklistに登録しました。
登録後、uBlocklistのリストをテキストデータとしてエクスポートし、下記スクリプトでテキストをJSONへ変換しました。

```sh:convert.sh
grep -E '^\*://.*/\*$' < ublacklist.txt \
  | sed -r 's!^\*://(.*)/\*$!{"type": "domain", "match": "literal", "domain": "\1"}!' \
  | jq -s > data.json
```

```sh:convert2.sh
grep -Ev '^\*://.*/\*$' < ublacklist.txt \
  | grep -Ev '^#.*$' \
  | sed -r 's!^\*://(.*?)/(.*)!{"type": "path", "match": "literal", "path": "\1/\2"}!' \
  | jq -s > data2.json
```

次に`data.json`と`data2.json`をマージします。

```sh:merge.sh
jq -s '[.[0], .[1]] | flatten' data.json data2.json
```

あとは適当にuBlock originとuBlacklistの書式を見て、それらのアドオンが解釈できるルールに変換するシェルスクリプトを記述すると完成です。

### なんでJSON？
* CSVやTSVより取り回しやすい
* 連想配列を使える
* 各種プログラミング言語でシリアライズ・デシリアライズ用のルーチンが出揃っている
    * 仕様である[RFC 8259](https://www.rfc-editor.org/rfc/rfc8259)が小さいので頑張れば自分でも書ける

### おわりに
はやくスパムが止むことを願います。

[^1]: あくまでもこの単語はイメージを簡単にするために使用しているものであって、私自身が「バズった」という単語の使用を推奨するものではありません。
[^2]: https://twitter.com/intent/user?user_id=1556852855700500480
[^3]: https://twitter.com/intent/user?user_id=1537020270749560832
[^4]: https://twitter.com/intent/user?user_id=1560957931008704512
[^5]: https://twitter.com/intent/user?user_id=1563149419469766656
[^6]: https://twitter.com/intent/user?user_id=1581223735092162562
[^7]: https://twitter.com/i/lists/1543983851135209473
[^8]: https://twitter.com/i/lists/1600043903872249857