それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

gitサーバのgogs を使うことに

github だけがgit webじゃない。

git をWEBで閲覧するのには、github 以外にも git serverとして gitweb でもなんでもある。

gitlab は要求水準が高いし、prometheus がCPU食いまくる、またgitlab は複数のドメインで運用が面倒だ。*1

gitlab を複数インスタンス入れるのも面倒な話だし。マルチドメインをできないのなら、別のgit web を探すことにして。 gogs に目をつけた次第です

gogs インストール

gogs は go で書かれたgit サーバー

packager を使うのが早い

https://packager.io/gh/pkgr/gogs/builds/689/install/ubuntu-16.04

パッケージでインストールする。

wget -qO- https://dl.packager.io/srv/pkgr/gogs/key | sudo apt-key add -
sudo wget -O /etc/apt/sources.list.d/gogs.list \
  https://dl.packager.io/srv/pkgr/gogs/pkgr/installer/ubuntu/16.04.repo
sudo apt-get update
sudo apt-get install gogs

設定ファイルが作られる

インストール完了したら、次の設定が作られる。

/etc/gogs/conf/app.ini

適当に設定ファイルを編集。

再起動

systemctl status gogs
systemctl restart gogs
systemctl status gogs

また、すでに起動しているので、インストーラーにアクセスしたいところがだが、MySQLを要求するので、先に作っておく

DB 作成

apt インストールが完了したら、あとは、DB設定とユーザー作成して登録する。

Gogs はMYSQLのDBを要求するので、MYSQLにテーブル作成ようにユーザーとDBスキームを作っておく

takuya@sakura:~$ mycli -u root
mysql root@(none):(none)> create database gogs
mysql root@(none):(none)> create user "gogs-user" identified
mysql root@(none):(none)> create user "gogs-user" identified by "**************";
mysql root@(none):(none)> grant all on gogs.* to 'gogs-user'@'%';
mysql root@(none):(none)>

接続テスト

ローカルホストと通信して、接続を確認する。

curl locahost:6000/install 

リモートなら、SSH の ポートフォワーディングでいいわ

ssh gogs-server -L 8080:localhost:6000
open localhost:8080

インストールして初期ユーザを作ったら準備完了

初回登録ユーザーが「管理者」

「1番目」のユーザーが自動的に管理者になり、2番目以降は通常ユーザーになる。

これは最初「アレレ、管理者設定どこ?」って思って勘違いしてググりまくって苦労した。2番目以降の通常ユーザーに管理者フラグを立てると管理者になれる。

メールの設定とポートとSSL

メール送信の設定とかを入れて、再起動する

あとは他に、ポート指定したり、nginx にSSLのポートなどを設定。起動ウイザードで設定する

最後に、pull / push の sshhttps のNATなしのポートをなどを設定して準備完了。

PAM / LDAP が使える

Gitlab で認証連携のコレらをやろうと思うと有料版など面倒なのだが、ユーザーの管理に PAM(/etc/passwdなど PAM対応してる認証機構ならなんでも) や LDAP(DN) とSMTPが使える。PAM対応してるのが熱い。

PAM対応があると、sshMySQL と共通のID/PWでユーザーを管理できるので、保守性が高くて複数インストールしても苦なく使える。

軽快

とても軽快で使いやすい。もっさり感もなく、要求スペックは高くない。

git の認知に関する愚痴など

「git は使いたいけどgithub はちょっと。」とか「github が導入できないから git 導入に苦労する」とかいう言説はまやかしである。SFTPでもSMB/Cifsやでも使えるのであるから。git は「分散」レポジトリであることを忘れて中央サーバーが必須だと思いこんでる人の多いことといったら。

github にアクセスできなくてもgit は使えるしソースコードの管理もできる。なんなら今回のようなgogs など git server をオンプレで立ち上げてもいい。

github イコール git と思いこんでる言説が多くて困る。

*1: X-Original-Host を見てくれればいいのにな。

Nature Remo mini を買ったのでローカルAPI叩いてリモコンのデータを取得してみる

未来の家に。

我が家も、スマート・ホームへの進化をします。スマートリモコン(学習型IR)で音声操作や外出先から操作するのは、小さい頃からの夢でした。でも一朝一夕で実現するわけでもないので、少しずつ準備をしていました。

Remoがやってきた

買いました。

早速APIを叩いてみます。

API を叩く前に、一通りの初期設定は終わっているものとします。 1. 開封する 2. 接続する 3. 登録する 4 .とりあえずなんかOn/Offは出来てる。

ローカルAPIでできること

  • GET / 最後に受信した、赤外線リモコンの波長(信号)の記憶を取得します。
  • Post / 任意の赤外線信号を指定して、それを発光して送信します。

つまり、これさえあれば、仮にNature Remo の運営会社が今すぐ倒産したとしても、Raspiなどから直接Curlでリモコン信号を叩けるわけです。 iOSのアプリが提供されなくなっても、WebUIからプロセス起動すれば動くわけです、やったね。

購入後、自己責任において、自由に使えるソフトウェアとハードウェアは本当に嬉しい。

ローカルのAPIへアクセスします。

curl  'http://Remo-1XXXXXX/messages' -H 'X-Requested-With: curl  ' -v

まだなにも出てきません。404 になると思います。

Remoに赤外線リモコンを受光させます。

Remoへ向かって赤外線リモコンを発光します、Remoが青色に反応したらOKです。

再度ローカルAPIを取得します。

curl  'http://Remo-1XXXXXX/messages' -H 'X-Requested-With: curl  ' -v

JSONが返ってきます。

返ってきたJSONの構造

次のようなデータが返ってくる。

{
  "format": "us",
  "freq": 37,
  "data": [
    8991,
    4505,
    550,
    1689,.... 
    525
  ]
}

ここで注目するべきは、 data 属性の値。

この値は、毎回同じにならない。たとえ同じリモコンで同じボタンを使って送信しても。同じにならないのだ。これは時間分解能の限界なので仕方がない。

ただ、比率は毎回ほぼおなじになっている。先頭2つは16T/8T ないし、8T/4T の整数倍に近い値になっている。

先頭2つは、その信号の補正でベースとなる波長の時間間隔Tを求めることができる。

リモコンデータをリピートする

取得したリモコンのデータをそのままオウム返ししてあげれば、まぁそのまま使える。

 cat power-on.json | curl-norc -X POST 'http://192.168.2.216/messages' -H 'X-Requested-With: curl' -d @- -vp://

リモコンのデータを解析

日本の家電の多くは、次のような仕様に基づいて、0/1 のバイナリデータ信号のオンオフ時間によって制御している。

先頭2つの時間合計を12で割ってみて、24で割ってみて、誤差を丸めてやり、時間T(変調単位)をもとめて、残りのペアをTの整数倍としてみてみる。

より1:1、1:3の整数値に近い方のTをみつければ、12/24のいずれかででNECとAEHAがわかるはずである。

f:id:takuya_1st:20190722225015p:plain

赤外線リモコンの通信フォーマット

今回、アイリスのLEDリモコンで試してみた。

仕様によれば、先頭の2つから、Tを求めて、あとはその整数倍のペアが出現するはずである。(赤外線の照射時間Tと整数比を測定するわけで、受光器の精度はmsである。機器は所詮整数倍しか見れない精度であろう。とすれば有効桁数は1桁の計測器である。2桁まで除算で計算し、それを整数値に丸めてやる)

import sys
import json

obj_txt = sys.stdin.read()
obj = json.loads(obj_txt)

code = obj['data']
data = ""
t = int((code[0]+code[1])/24)

data = [ [ code[i], code[i+1] ] for i in range( 2, len(code)-1,2) ]
data = [ [ round(code[i]/t), round(code[i+1]/t) ] for i in range( 2, len(code)-1,2) ]

print(data)

実行結果は次のようになった。

[[1, 3], [1, 1], [1, 1], [1, 1], [1, 3], [1, 1], [1, 3], [1, 1], [1, 1], [1, 3], [1, 3], [1, 1],...]

ここで、仕様を見ると、 [1,1] (すなわち [1T,1T] ) は 0 を示し、[1,3] は 1 を示す。 これを使って0/1 にマッピングしてやり、2進数表記を得たら、4ビットずつ16進数表記にしてみた。

import sys
import json

obj_txt = sys.stdin.read()
obj = json.loads(obj_txt)

code = obj['data']
data = ""
t = int((code[0]+code[1])/24)

data = [ [ code[i], code[i+1] ] for i in range( 2, len(code)-1,2) ]
data = [ [ round(code[i]/t), round(code[i+1]/t) ] for i in range( 2, len(code)-1,2) ]
data = [ "1" if e == [1,3] else "0" for e in data ]
data = [ "".join(data[i:i+4]) for i in range(0,len(data)-3,4)  ]
data = [ int(e,2) for e in data  ]
data = [ format(e , 'x') for e in data  ]
data = "".join(data)

print(data)
cat led-on.json | python decode-LED.py
8a6e0800800036

あとは、これをボタンごとに調べてやると、ボタンごとの差異が明確になるはずである。

さらに、ボタンごとの差異から、リモコンでは実装されてないOn/Offが見つかる可能性もある。

さらに、この整数値を時間間隔に書き直してRemo経由で発光してあげれば、照明のリモコンとして動作する。

といってもアイリスのLEDはプリセットに含まれているので、ここまで計算する必要も無い。これ以上は時間の都合上やる意味もないが、もし非対応のリモコンが出てきたときにどうやってデータを取得するかだけメモを残しておく

残念なことに

ローカルAPIでは、リモコンの送受信、つまりGET/POSTしかできないようです。

関連商品

Nature Japan Nature Remo REMO-1W2

Nature Japan Nature Remo REMO-1W2

参考資料

Nature Remoに存在しないボタンを登録する - 暇な女子高専生のブログ

curlコマンドで ~/.curlrc の設定を有効無効を切り替える

curlrc でよく使うオプションを入れておくと便利

curl でよく使う設定をまとめる ~/.curlrc - それマグで!

便利なのですが、ついつい入れすぎてしまって、いざというときに不要なファイルを消せない。

どういうことかというと、~/.curlrc が存在してると最優先でそれを使うので。

解決策 Aliasなどと組み合わせる

alias curl-with-json=curl -q -K ~/.curl-json.conf
alias curl-with-my=curl -q -K ~/.curl-my.conf

その他の解決策

必要のないときだけ、デフォルト値を明示して使う。

alias curl-ddefault=curl -q -K ~/.curl-my.conf

ポイント

curl で curlrc を「使わない」ときは -q を先頭にかいて --config/-K を その次に書く

curl -q --config /dev/null

参考

man curl

すぐわかる標準エラー出力と標準出力の捨て方( /dev/null へリダイレクト

だれですか ' &1' なんてファイルを作ったのは。

サーバーにログインしてみてたら'1' っていうファイルがあるんですね。1という名前のファイルがあるんですよ。

どう考えても、リダイレクトに失敗してますよね。

標準エラー出力を捨てる速攻で覚えるの書き方

command  &> /dev/null

bash ならもうこれだけ覚えてほしい。

個別に指定する場合

個別に指定する方法が一番基本なのでこれをまず覚えてほしい。

commdn  2>/dev/null  >/dev/ null

アンパサンド(&) の指定でミスるなら

もう、アンド使うなといいたい。

DoH:DNS-over-HTTPS なサーバーを作って試す。

DoH サーバーを作って問い合わせをちょっとだけ秘密にする。

DNS によるブロッックングが2019 上半期の一番の話題だったと思う。DNSブロッキングはUKで実際に運用されていたり、法制度化されているので本邦でも導入するべきと言った論調だった。児童ポルノでも一定の成果を上げているしーみたいな?まぁお手本にしたUKや中共ではプライバシー保護の議論は常にあるし、我が国も早晩、プライバシー保護と監視の両立を迫られることになる。その際にブラウザがDoHで問い合わせを保護する方法は重要に担ってくると思う。

DoH DNS over HTTPS を体験してみる

DoH を体験しておけば、問題点や課題が少しでもわかるのではないでしょうか。そうおもって使ってみることにしました。

DoH なサーバーを作る

DoH は中間にめっちゃいろいろ挟まるので、最初に概要だけ書いておきます。

dns-https クライアント → Webサーバー(ssl処理) → dohプロキシ → unbound(DNS問合せ)

DoH プロキシは 今回、python のpip で導入します、多種実装があります。

ブラウザ→WEBサーバのSSLはLetsEnctyptで導入されているものとします。*1

DoHプロキシの準備

インストール先を作って pipenv 環境を整える

target=/var/www/virtualhosts/dns.example.com/doh
mkdir -p   $target
cd  $target
pipenv install 
pipenv run pip install pip --upgrade
pipenv run pip install doh-proxy

pipenv は導入されているものとします。

doh を起動します。

pipenv run doh-httpproxy --level DEBUG \
  --upstream-resolver 192.168.1.1 \
  --listen-address=127.0.0.1 \
  --trusted=127.0.0.1 \
  --port 8053

ここでは、DoH プロキシを起動しています。

--upstream-resolver 192.168.1.1 では、DoHプロキシがDNSの実レコードを問い合わせるリゾルバを指定(ルータとか unbound とか ISP DNSとか public DNSとか)

--listen-address=127.0.0.1 --trusted=127.0.0.1 --port 8053 では、DoHがリッスンするIP/ポート。さらに信頼するHTTP中間プロキシのIPを記述

https する nginx の設定例

httpsTLS通信を nginx に任せることにするので、該当のWEBサーバの記述を作ります。

nginx ではSNIでドメイン名を受け取り、それを先程のDoHサーバーに転送します。

# vim: ft=nginx ts=2 sw=2 sts=2

server {

  server_name  dns.example.com;

  add_header  X-Robots-Tag "noindex, nofollow, nosnippet, noarchive";

  listen 443 ssl http2;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

  if ($scheme = http) {
    return 301 https://$server_name$request_uri;
  }


  location /dns-query {
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect off;
    proxy_buffering off;
    proxy_pass http://127.0.0.1:8053;
  }
}

設定ができたら、リロード再起動

sudo nginx -t && sudo service nginx reload

最後に接続確認

nginx とdoh-プロキシの準備と起動すべてが終わったら。接続してみる

pyenv run doh-client --domain dns.example.biz --qname t.co --qtype a

応答例

2019-07-16 15:10:13,417:    DEBUG: Opening connection to dns.example.biz
2019-07-16 15:10:13,423:    DEBUG: Query parameters: {'dns': 'AAABAAABAAAAAAAAAXQCY28AAAEAAQ'}
2019-07-16 15:10:13,424:    DEBUG: Stream ID: 1 / Total streams: 0
2019-07-16 15:10:13,428:    DEBUG: Response headers: [(':status', '200'), ('server', 'nginx/1.10.3'), ('date', 'Tue, 16 Jul 2019 06:10:13 GMT'), ('content-type', 'application/dns-message'), ('content-length', '293'), ('cache-control', 'max-age=378'), ('x-robots-tag', 'noindex, nofollow, nosnippet, noarchive')]
id 0
opcode QUERY
rcode NOERROR
flags QR RD RA
;QUESTION
t.co. IN A
;ANSWER
t.co. 378 IN A 104.244.42.133
t.co. 378 IN A 104.244.42.5
t.co. 378 IN A 104.244.42.69
t.co. 378 IN A 104.244.42.197
;AUTHORITY
t.co. 12577 IN NS ns1.p34.dynect.net.
t.co. 12577 IN NS ns2.p34.dynect.net.
t.co. 12577 IN NS d01-02.ns.twtrdns.net.
t.co. 12577 IN NS c.r06.twtrdns.net.
t.co. 12577 IN NS ns3.p34.dynect.net.
t.co. 12577 IN NS a.r06.twtrdns.net.
t.co. 12577 IN NS b.r06.twtrdns.net.
t.co. 12577 IN NS ns4.p34.dynect.net.
t.co. 12577 IN NS d01-01.ns.twtrdns.net.
t.co. 12577 IN NS d.r06.twtrdns.net.
;ADDITIONAL
2019-07-16 15:10:13,432:    DEBUG: Response trailers: {}

サーバーのログの例

curl 単体接続で見れないの?

専用クライアントを経由して見てますが、curl で問い合わせるには、hexdump して base64エンコードしないとダメなので、そのままでは見られなかった。

curllocalhost:8053 でdoh-proxy と直接通信する例。

 echo -n 'q80BAAABAAAAAAAAA3d3dwZnb29nbGUDY29tAAABAAE=' | base64 -d \
\
 | curl -s -H 'content-type: application/dns-message' \
 'http://localhost:8053/dns-query' \
  -H 'X-Forwarded-For: 127.0.0.1'\
  --data-binary @-| hexdump -C \

ハッキリ言ってめんどくさい。

https://www.secjuice.com/modsecurity-web-application-firewall-dns-over-https/

Firefoxで使ってみる

手早く試すには、Firefox でDoHサーバーを使うのが良いと思います。

わかったこと

443ポートでSNIするから、ポート53が必要なくなる。通常のWEBと同じくHTTPSドメイン名で待ち受ける事ができるので便利。443の用途がまた増えてしまった。

HTTPSをするので改竄やオレオレが難しい。クライアントは安全になる。

DoHプロキシとUnboundの通信は暗号化されないし丸見えで従来どおり。全く今までどおり。

対応クライアントがFirefoxくらいしか無い。iOSが対応したら嬉しいな.

ただし、nginx で待ち受けてるDNSホスト名の名前解決には、従来どおりのDNSが必要。ここで詐称される可能性はあるがHTTPSで改ざん検出は可能かもしれない。しかし証明書の確認のためにCRL引っ張りに行くのもまたDNSが・・・ああエンドレスリピートは変わらない。

一般市民が、public DNS経由でブラウザを使うだけならかなり安全になるかと思う。

2023-06-05

記述ミスを修正

参考資料

https://facebookexperimental.github.io/doh-proxy/tutorials/nginx-dohhttpproxy-unbound-centos7.html

*1:めんどくさければCloudfrontとかのhttpsCDN挟んでください。

amazonの検索結果からボッタクリ価格業者を消す方法 をiOS でも使えるようにショートカット.app にした

iOSブックマークレットの代わりに'ショートカット.app' を使う。

経緯;Amazonガチャにもうヘトヘト

Amazon の商品検索から、中華出品者のゴミを消したい。プライムで返品可能とはいえ、もうAmazon中華ガチャに疲れた。海外サイトで購入するより、返品ができるとの理由でAmazonで買ってガチャを引いていた。 AliexpressやeBay での返品不能のリスクを減らすためにプライムに加入しているが、もう外れ多すぎてガチャ引くのに疲れた。

Amazon 以外の出品者を削除する

Amazon以外の出品者を除外する(つまり、出品者がAmazon JP なものだけに絞ることができる)

次の出品者コードに限定することで実現する。

&emi=AN1VRQENFRJN5

internet.watch.impress.co.jp

iOS で使えないじゃん

世の中にはブックマークレットがあるけど、iOSではBookmarkletが動かないので、iOS の 'Shortcuts.app' にシェアボタンで渡せるようにしました。

Amazonが出品してる商品に絞る←インストールはこちらから

f:id:takuya_1st:20190716142812p:plain:w200

使い方

Amazonを開いて

f:id:takuya_1st:20190716143002p:plain

シェアボタンからショートカットを呼び出し、

f:id:takuya_1st:20190716143008p:plain

該当のショートカットプログラムを起動する

f:id:takuya_1st:20190716143013p:plain

きれいになる!!

f:id:takuya_1st:20190716143021p:plain

おお素晴らしい!!

中身の概要

単純に replace text して、Safariで開き直すだけ。

f:id:takuya_1st:20190716143412p:plain

関連資料

http://n-styles.com/main/archives/2017/04/14-054444.php

https://www.icloud.com/shortcuts/793e333499d4408c8b6ca868af14e330

アレな出品を一括除外? Amazonの検索結果をクリーンにできる「魔法の文字列」が話題に【やじうまWatch】 - INTERNET Watch

https://twitter.com/takuya_1st/status/1150825108925083651

jq コマンドで UTF-8 の文字列をデコードやエンコード(codepoint を元に戻す)

コードポイントなった、日本語を単純に元のUTF-8に戻したり、コードポイントでエスケープして符号にする。

コードポイントになった文字列*1

単純に jq に通せば、日本語になる。

何も考えずに、 jq 通せばコードポイントを読める文字にすることができる・

root@acid:~# cat out | \jq - '.dir'
~/ダウンロード

逆に、コードポイントのママほしい

-a オプションをつけて、ASCIIにエンコードするとちゃんと出てきます。やったね。

root@acid:~# cat out | \jq -a  '.dir'
"~/\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9"

*1:正確にはエンコード・デコードという用語が正しくないかもしれない

jq コマンドなどで、JSONハイフン付のキーを取り出す方法

jq ではハイフンに意味がある

オブジェクトのキー名にハイフンが混じるとエラー

$ cat out | jq - .download-dir
jq: error: dir/0 is not defined at <top-level>, line 1:

なぜ?

だってJSってハイフンは引き算じゃん?

こう書いてしまうと、

obj.config ={".download-dir": "~/Downloads"}

obj.config.download-dir # あ!?

どう考えても、引き算じゃん?

obj.config.download-dir
(obj.config.download - dir)  // え?

なので、JSONにハイフンの引数を入れるのはあまり推奨されないけど、JSONを単なるシリアライズだとか、データ保存形式とか、設定ファイルだと思ってる方々はついついやりがちなのです。

jq ではクォートか、ハッシュアクセスを使う

jq でも同じです。ちゃんとクォートつけるか、「 [] 」 でアクセスする

# cat out | jq -ra '."download-dir"'
~/Downloads
root@acid:~# cat out | jq -ra '.["download-dir"]'
~/Downloads

だめな例

おかしがちなだめな例。

これは、ダブルクォーテーションマークが、Bashに解釈されるときに外されて jq まで届かない。

# cat out | jq -ra ."download-dir"

これは、jq がシェル経由という落としな穴。

JSON は意外な落としな穴がある。

何でもかんでもJSONってやめたほうが良いよまじで。手入力とか設定ファイルにはホント向いてないから。

手作業に向いてないってことはデバッグとかで、データ取り出しが本当に煩雑。

忘れ去られゆくキーボード・ショートカット1 タブキーによる項目移動

キーボードショートカットが日本では忘れ去られようとしている

いつの頃からか、キーボードを使うのは「悪」という監査が蔓延っているようです。キーボードから直接入力することが危険だそうです。

f:id:takuya_1st:20190706170308p:plain ローソン銀行の例

絶滅危惧種のキーボード・ショートカット:タブキー

いまや絶滅危惧種になってしまった。「タブキーを知りません」と「入力時に押したことないです。」という人は、90%を超える(個人調べ)だろう。

自称:情強の情報系学生でも、タブキーを単体で殆ど使っていません。Alt+TabやCtr+Tabだとまだ使われているが、タブキー単体で押す人は殆ど皆無だと思われる。

タブキーはフォーカス移動

タブキーによるフォーカス移動を知らないのである。というかフォーカスを概念として知らない。

タブキーとエンターは組み合わせで使うものなのですが、「マウスカーソルを移動しクリック」だけが正しい操作だと倣っているのでしょう。タブキーをおしてエンターを押せません。

アプリケーションやウェブブラウザの入力項目はタブキーで移動することができます。エンターで選択することができます。

しかし、jQuery などで実装されたモーダルウインドウには「全く」これらのことが配慮されていません。タブでフォーカス移動もできない、Enterでクリック代替をすることもできません。中途半端な実装のモーダルウインドウのライブラリは滅びていいと思います。

また、jQeury で実装されたフォーム項目には対象項目を非表示のママ実装されているものがり、タブ移動ができない入力フォームが数多くあります。残念なことです。

タブキーが実装されている例

Twittertweet フォーム。

f:id:takuya_1st:20190706170827p:plain

f:id:takuya_1st:20190706170810p:plain

タブキーが忘れ去られると困ったことになる。

タブキーは「ハンディキャップ」の人たちにも大変有益だと思う。バリアフリーを声高に叫ぶ割に、身近なキーボードのキーを使わないまま配慮を忘れ去られゆく。

駐車場に車椅子のスペースを作るのと同じくらいWEBサイトや入力フォームにおけるTabキーは重要です。完全に愚痴でしかないが、日本では本当に軽視されていて、できれば政府が主導してガイドラインを定めるべき案件です。日本政府がいかにIT無能かわかるのではないでしょうか。

iOS にはタブキー相当の「入力項目の移動」があります。

iOS を見てみると、タブキーと呼ばずに「上下」の項目移動があります。これがPCのキーボードのタブに相当します。ところがほとんど認知されていません。悲しい限りです。

f:id:takuya_1st:20190706171951p:plain

さらにひどい悲しい事実として知ってほしい。この「入力項目の移動ボタン(タブキー)」が邪魔で消したいという人が後を立ちません。Q&Aサイトではよく質問で上がってきます。利用者からだけでなく、開発者のQ&Aサイトでもクライアントに言われたから消したいとう書き込みを何度か見かけたことがあります。

タブキーという呼び方が「ブラウザのタブ」とかぶる

タブキーという呼称が、残念なことに、ブラウザのタブと同じ音で同じスペリングのために、タブについて調べることが事実上不可能になっています。

また、タブといっても伝わらないので、タブキーと言わないと伝わらないことが多いです。これも希少化に拍車を掛けているのではないでしょうか。

タブはインデントだと思われている

「タブキーはインデント」のためにあると思いこんでいる人も多い。タブといえば、スペースとタブで宗教論になることも多いです。そのためタブで項目移動は忘れ去られゆく。

海外のサービスはWEBでもSPAでも比較的Tabキーを実装している

Slackなどもタブキーで項目移動をきっちり実装してたりします。tabindex を無視するスタイルなのは、日本の大手企業のWEBサイトによく見られます。イオンとかセブンとかローソンとか。

もしかしたら海外ではちゃんとdisabled people に対して配慮しているのか、スピード狂のためにTABキーを実装するのが文化として根付いてるかもしれない。

タブキーによる項目移動の使い方:tabindex

タブキーはフォーカス移動をして使うものです。

TABキーとShift+TABキーがペアで使われます。決定はEnter(またはSpace)を押します。

フォーカスを外したいときはESCです。

タブキーとESCとEnterはペアで使います。

これだけです。

開発者は、フォームの項目にtabindex を入れれば良いのです。入れなくても左上から順番に項目が選ばれます。フォーカスしたくない(ちょっと隠してたりdisabledなinput) なら -1 をいれてタブフォーカスを無効にすれば良いわけです。

このブログを書いているはてなブログでも、編集画面にはタブキーによるtabindex の項目移動は実現できていません。

Windows もTABキーを忘れようとしている。

Windows10から搭載された設定画面とエクスプローラーでは、以前ほどタブキーを使えないことが多いです。彼らもタブキーの存在を忘れてしまったのでしょう。

タブキーの存在

私達は、タブキーによる項目移動とフォーカスという概念を徐々に失っていると思います。

わたしとタブキーの出会い。

私は、タブキーをいつから使っているか思い出せません。パソコンを使い始めたのが2005 年ごろなのでそれ以降であることは間違いないです。ノートPCにして、マウスを捨てたのが2010 年頃なので、多分その頃から本格的に使ってると思います。

いまでは、タブキーで「はい・いいえ」を移動したり、「キャンセル」を押したり、入力フォームを手早く移動したり、無くてはならない存在ですが、徐々に使えない箇所が増えていて悲しい。

タブキーが使えると早いのに

タブキーが使えると入力が圧倒的に早くなります。RPAとかバズワードが飛び交ってますが、自動入力と定形入力の高速化より、まず入力者であり操作者であるわたしたちがタブキーによ入力高速化をしたほうが良いと思う。しかしそうなっていないのが少し残念。

多く人はタブキー忘れてしまったのでしょうか。

Windowsエクスプローラと設定もタブキーで操作しにくくなり、ウェブのjQuery モーダルはタブキーが動かず、iOS では邪魔者扱い。Excel入力でもタブ移動より矢印カーソルやマウスが好まれる。はてなブログでもタブキーで右側メニューを選べない。

このままタブキーによる項目移動は絶滅していく運命にあるのでしょうか。

タブキーめっちゃ使うよ!!って人がいたらコメントくだされば嬉しいです。

メールアドレスの入力が、@マークで分割された場合の簡単入力

誰が考えたか知らないが、謎文化のメアドを区切る文化

f:id:takuya_1st:20190706160501p:plain

入力がかったるくて仕方ない。思考するより速く入力したいスピード狂としてはストレスを感じる

ストレスを感じるより、プログラミングして解決したほうが気持ちがいい。

対策した

そこで、XpathBookmarklet を組み合わせて対処することにした。

(function(){
  maddr = []
  email = window.prompt("メールアドレス?", "");
  maddr = email.split(/@/);
  
  mail_inputs = [];
  ret = document.evaluate("//*[ count(./input[ contains( translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'email') ]) = 2 ]//input", document );
  while ((input = ret.iterateNext())) {
      mail_inputs.push(input)
  }
  mail_inputs.forEach( function(e,i){
    e.value = maddr[i%2]
  } )
})()

実行結果

メアドを貼り付ければ、簡単入力ができる。はー楽。

f:id:takuya_1st:20190706161757p:plain

f:id:takuya_1st:20190706161823p:plain

自動入力という概念がないSI'er世界。

これは愚痴なのですが、日本語の企業サイトには、「自動入力は悪」という概念があるようで。手入力より自動入力のほうが間違いが少ないっていう記述を見かける。 本当に何を考えているのかわからないし。フォームを分割したところで、ヒューリスティックな対処法でしかなく、経験則によりサポートコストが減るというのなら、リーンスタートアップ的にいえばA/Bテストで比較するべきなのである。フォーム項目を増やしても工数が増えるだけだし、RichUIとかUXとか言ってたりフォームをデザインするデザイナは、もっとA/Bテストをプッシュするべきだと思います。

関連記事

謎フォームの入力に苦労したので解決した話など

Xpath の contains で大文字小文字を区別しない(no case / insensitive match)

世の中には、@アットマークで、メアドを区切るという謎文化があります。

「メールアドレスをご入力ください」ただし、アットマークの前後を分けて。フォームの入力がすごくめんどくさいものがあります。

もっと手軽に入力したくてBookmarkletで対処するんだけど。大文字小文字を区別するのがめんどくさい

f:id:takuya_1st:20190706160501p:plain

*1

大文字小文字を区別しない、Xpathの例

$x("//*[ count(./input[ contains( translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'mail') ]) ]//input")

ポイント

ここで、先に大文字小文字を全部小文字にして丸める。

translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')

その後に、マッチさせる。

 contains( translate(@name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'mail')

これで、大文字小文字を考えないマッチングができる。

ほんと、Xpathって便利ですね。世間は、もうCSS セレクタばっかり使っってるだろうけど、私は、未だにXpath手放せないや

参考資料

https://stackoverflow.com/questions/8474031/case-insensitive-xpath-contains-possible

*1:こんなことをしてるの、日本語の大手企業のサイトだけで。これやるとIT能力低いことの暴露だと思うんですけど

我々のDNS問い合わせは監視されている。

ACTIVEに基づく通知が来た。

この日、私は実験目的でヤバそうな各種DNSを引いていたのですが、その結果ががこれである。

どのURL(ドメイン)がフィルタリングされたか全くわからないし、ACTIVEの対象ドメインが完全非公開なので怖いなと思った。

フィルタリングされてるかされてないか、比較するためにも各種テクニックは知っておいたほうが良いな

そのうちIPアドレスで停止されるんだろうけど、通信監視とは怖い世の中だ。

f:id:takuya_1st:20190701171753p:plain

f:id:takuya_1st:20190701171756p:plain

mydns 関連のドメインが 1.1.1.1 のpublic dns から引けない問題(DNSフィルタリング・規制か?)

twitter を見ていると、MyDNSが引けないというツイートを見かけた。

引いてみた。

takuya@untitled1$ dig aaaaaa.mydns.jp @1.1.1.1

; <<>> DiG 9.10.6 <<>> mydns.jp @1.1.1.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 25043
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1452
;; QUESTION SECTION:
;mydns.jp.          IN  A

;; Query time: 2209 msec
;; SERVER: 1.1.1.1#53(1.1.1.1)
;; WHEN: Mon Jul 01 16:00:36 JST 2019
;; MSG SIZE  rcvd: 37

ちゃんと引ける。ほかのところからも引ける。

takuya@untitled1$ dig +short xyz.mydns.jp   @dns-a.bbtec.net
163.44.151.xxx
takuya@untitled1$ dig +short xyz.mydns.jp   @8.8.8.8
168.235.75.xxx
takuya@untitled1$ dig +short xyz.mydns.jp   @1.0.0.1
takuya@untitled1$ dig +short xyz.mydns.jp   @1.1.1.1

Cloudflare から引けない問題。。。

これはDNSフィルタリングなんだろうか。public DNS がフィルタリングを始めたとなると本当に怖い世の中になったと思う。

追記:あとで確認したらTRACEはできる。

1.1.1.1 にたいして、何度かdig +trace を投げつけておくと、キャッシュされるみたい。+trace 後は通常通りDNSレコードを応答してくれる

takuya@untitled1$ dig +short a.mydns.jp   @1.1.1.1
takuya@untitled1$ for i in {1..10}; do echo $i; dig a.mydns.jp   @1.1.1.1 +trace > /dev/null  ;sleep 0.1  ; done
1
2
3
4
5
6
7
8
9
10
takuya@untitled1$ dig +short a.mydns.jp   @1.1.1.1
168.235.75.38
210.197.74.203
46.19.34.8
107.191.99.190
163.44.151.204
takuya@untitled1$

不思議で仕方ないので少し考えてみた。

ここから考えると、Cloudflare自体のDNSに問題はなく、mydns側の ns レコード(ns[0-2].mydns.jp)の設定に難があってCloudflareがうまくDNSをたどってないのではないか

そう考えると、ns レコードを引けていないので、たぶんmydns 側とcloudflareが使ってる再帰サーバーがうまく引けないのかもしれない。

takuya@untitled1$ dig mydns.jp    ns  @8.8.8.8 +short
ns1.mydns.jp.
ns2.mydns.jp.
ns0.mydns.jp.
takuya@untitled1$ dig mydns.jp    ns  @1.1.1.1 +short
takuya@untitled1$

いずれにせよ、特定のDNSサーバーを参照すると、DNSによる名前解決が止まってしまうのは困った問題だと思う(止められているならもっと怖い。)

openwrt で /etc/resolv.conf の dns サーバーを常に固定する

openwt で dns サーバーを指定する

OpenWRTでDNSサーバをあれこれいじってたので、メモ。

ルータのDNSサーバーを指定するには /etc/resolv.conf ( 実態は /tmp/resolv.conf ) にあります。

これは起動すると、自動的に生成されるresolv.confファイルで、PPPoEやDHCPv6などネットワーク接続後に更新されるファイルでもあります。

固定したい

openwrt がどのDNSサーバーから名前解決するかを固定したい

たとえば、nameserver をつねにlocalhost の unbound に固定したいとかある。

root@openwrt:~# nslookup  t.co
Server:     127.0.0.1
Address:    127.0.0.1#53

Name:      t.co
Address 1: 104.244.42.197
Address 2: 104.244.42.5
Address 3: 104.244.42.69
Address 4: 104.244.42.133

ネットワーク設定からやる

cloudflare の 1.1.1.1 をつねに自身の名前解決につかうには、LANネットワーク設定から行う

uci network.mylan.dns=' 1.1.1.1 8.8.8.8 8.8.4.4'

設定を書いて適用後

これを書いておくと、次のようにDNSの名前解決順序が適用される。

root@tplinkc7v5:~# cat /etc/resolv.conf
# Interface lan
nameserver 1.1.1.1
nameserver 8.8.8.8
nameserver 8.8.4.4
# Interface wan6
nameserver 2001:xxxx:8383:xxxxx:a5xx
search flets-xxxx.jp
search iptvf.jp
# Interface PPPoE-ISP
nameserver ISPのDNS1
nameserver ISPのDNS1

DNS の項目はいくつもあるので注意

OpenWRTルータ設定のDNS設定項目はいくつもあるので注意が必要

  • PPPoE / LAN ごとのDNS設定 ( uci show network.lan.dns )
  • ルータ自身のDNS設定( /etc/resolv.conf ← LAN設定に依存)
  • DNSMasq が問い合わせる先の設定 ( uci show dhcp.@dnsmasq[0].server
  • DNSMasq はDHCPと一体化している
  • DHCP サーバがIP配布時に通知するDNSサーバー設定 ( uci show dhcp.lan.dhcp_option//='6,192.168.11.1' )

今回使ったOpenWRT

root@openwrt:~# cat /etc/openwrt_release | grep RELEASE
DISTRIB_RELEASE='18.06.2'

参考資料

https://turedure-plog.blogspot.com/2014/10/openwrtgoogledns.html

unboundでrootから引くdnsサーバを作り、DNSフィルタリングに備える

この記事は試験的なものです。

ちゃんと動作するか現在、調査検討中です。

public DNSDNSブロッキングされる可能性がある。

public DNS 1.1.1.1/ 8.8.8.8 は多くの人が使っていて、とても公共性が高いのですが。多くの人が使うがゆえにフィルタリングされ自由を失う懸念が拭えない。

IIJの例

IIJ Public DNSサービス

DNSフィルタリング・ブロッキングについて 本サービスでは、インターネットコンテンツセーフティ協会(ICSA)が定める基準に則り、児童ポルノ対策のためのDNSブロッキングを実施しています。 なお、IIJが2019年7月より順次導入予定の「マルウェア対策のためのDNSフィルタリング」は実施いたしません。

DNS の名前解決がロギングされる。

どのドメインのIPを調べたのかの名前解決が残されます。DNSのフィルタリングとロギングはDNSサーバへの問い合せを記録し、その内容を保存調査分析します。ということはログ収集機構が組み込まれている。

DNSブロッキングは、オプトアウトしない限りログは収集される。またオプトアウトしても懸念は残る。 分析はしないと言ってるが、ロギング をしない とはどこにも書いていないので、ロギングされているのであろう。また「オプトアウトした」という情報が漏れる懸念がある。つまり私達がどのサイトをみたのかドメイン名で丸わかりになってしまう。そして、ISPはこれらの個人情報をいつもどおり任意で警察に提供する懸念がある。警察の任意取得が問題視されてから任意をやめるというTポイントのパターンを悪用される懸念がある。

IIJの例

IIJのセキュリティに関する取り組み | インターネットイニシアティブ(IIJ)

分析はしないとはいってるけど、蒐集しないとは言ってない。

自前でDNS をrootなserver から引いてくれるDNS問い合わせサーバを作りたい。

これらを踏まえると、ISPへのDNSサーバーへの問い合わせの記録は漏れるものです。プライバシーは保護されるか全く見通したが立たない。そこでDNSの問い合わせは、root サーバから自分で引いてくる必要がある。DNS用意しても、ISPや/1.1.1.1/8.8.8.8にフォワードしたらプライバシーが丸見えで意味がない。

DNSの問い合わせ用のサーバを作って運用してみようと思い立った。要は、オレオレpublicDNS です。

自分自身で、root からDNSを引っ張ってくるサーバを持っていれば、ISPgoogle(8.8.8.8)にどのサーバに問い合わせたかのプライバシー情報が漏れ無いと考えた。

今回のポイント forwardしない。

よくあるdnsサーバーのインストール記事だと 8.8.8.8へforward するだけです。

今回は、ISPやpublicDNSへ フォワードせず に自力で名前解決を試みます。

今回使ったもの - unbound

debian / unbound で構築してみました。

インストール

unbound のインストール。とにかくこいつがないと始まらない。

sudo apt install unbound 

あと、必要に応じて dns の問い合わせを確認するコマンドを入れておく

## drill コマンドのインストール
sudo apt install ldns-utils
## dig コマンドのインストール
sudo apt install dns-utils
## unbound-hosts コマンドのインストール
sudo apt install unbound-hosts

これらのコマンドは必要に応じてdnsの問い合わせを確認するのに使います。

私はDebianで実験しています。ubuntu の場合はdns-utilsではなくdnsutilsです。

基本設定

/etc/unbound にある設定を変えていきます。

debianの場合は次のようなディレクトリ構造になっていました。

takuya@:unbound$ tree .
.
├── unbound.conf
├── unbound.conf.d
│   ├── qname-minimisation.conf
│   └── root-auto-trust-anchor-file.conf
├── unbound_control.key
├── unbound_control.pem
├── unbound_server.key
└── unbound_server.pem

/etc/unbound/unbound.conf.d/qname-minimisation.conf

Serverの項目を変えていきます。

ここでは、指定したネットワークアドレス範囲からの問い合わせを許可。 また、unbound がListenするIPアドレスを指定した

server:

    #qname-minimisation: yes
    #
    access-control: 192.168.0.0/16 allow
    interface: 192.168.11.1
    root-hints: root.hints

root-hints は次で準備します。

root.hints を用意、root から問い合わせしてたどるようにする

root-hints ファイルを入れると、root の nameserver '.' からたどるようになります。

curl --output /etc/unbound/root.hints https://www.internic.net/domain/named.cache

root.hints ファイルの中身は、ROOT-SERVERSのIPアドレスです。 半年に一度くらいは更新するようにするといいらしいです。。

設定したら再起動とと動作確認

systemctl restart unbound で再起動

unbound-hosts で動作テスト。

unbound-host を使って動作テストをしてみます。

takuya@:unbound$ unbound-host -4 -d pbs.twimg.com

動作テスト dig

dig @192.168.11.1 twitter.com

これで、unbound のサーバーになります。

dig +trace できるようにする。

このままでは、IPの応答はできるけど、なにかしらトラブルのときに問い合わせを +trace できないので、 dig クライアントが trace コマンドを使えるようにします。

#    access-control: 192.168.0.0/16 allow 
access-control: 192.168.0.0/16 allow_snoop

traceするときは、クライアントが再起問い合わせをするので、サーバーが再起問い合わせをする必要がないですよね。 なので、クライアントが非再起問い合わせをしてくるので、それを許可するわけです。

+trace してみる

snoop をオンにすると dig +traceができるようになります。やったね。

dig +trace   pbs.twimg.com @192.168.11.1

; <<>> DiG 9.10.3-P4-Debian <<>> +trace pbs.twimg.com @192.168.11.1
;; global options: +cmd
.           448024  IN  NS  d.root-servers.net.
.           448
(中略
pbs.twimg.com.      300 IN  CNAME   cs196.wac.edgecastcdn.net.
;; Received 81 bytes from 204.13.251.34#53(ns4.p34.dynect.net) in 15 ms

unbound-anchor は自動的に更新される

systemctl restart unbound で再起動したら、 root.key のアンカーは自動的に更新されるようですね。

takuya@:unbound$ sudo systemctl restart unbound
takuya@:unbound$ cat "/var/lib/unbound/root.key"
; autotrust trust anchor file
;;id: . 1
;;last_queried: 1561371009 ;;Mon Jun 24 19:10:09 2019
;;last_success: 1561371009 ;;Mon Jun 24 19:10:09 2019
;;next_probe_time: 1561411721 ;;Tue Jun 25 06:28:41 2019
;;query_failed: 0

今回試したこと

unbound と root.hints を使って、カジュアルに呼ぶならオレオレpublic dns 的なものを作った。正しくは再起問い合わせのリゾルバ。

DNSブロッキングに備える。

DNSブロッキングDNSのロギングは、いつどこで誰に提供されるか全くわからない。そのため自分でDNS再起問い合わせをできるようにして自衛に努める必要がある。

追記 可能であれば、iptablesISPDNSやpublicDNSを止める

疎通確認をどうするか。可能であれば設定後にUnbound以外のDNSiptables でフィルタリングしてしまうのが良いと思う。

たとえば、yahoo bb のDNSサーバーとの通信を停止してDNS名前解決がソフトバンクに流れないようにする。

Chain zone_wan_output (1 references)
target     prot opt source               destination
output_wan_rule  all  --  anywhere             anywhere           
zone_wan_dest_REJECT  tcp  --  anywhere             dns-b.bbtec.net      tcp dpt:domain 
zone_wan_dest_REJECT  udp  --  anywhere             dns-b.bbtec.net      udp dpt:domain 
zone_wan_dest_REJECT  tcp  --  anywhere             dns-a.bbtec.net      tcp dpt:domain 
zone_wan_dest_REJECT  udp  --  anywhere             dns-a.bbtec.net      udp dpt:domain 
zone_wan_dest_ACCEPT  all  --  anywhere             anywhere             

追記: 簡単なパフォーマンス測定

cloudflare の 1.1.1.1 と google の 8.8.8.8 と、今回のunbound、そして dnsmasq で 1.1.1.1 にフォワードする ルーターで、簡単に応答時間を比べてみました。

takuya@:unbound$ for dns in 1.1.1.1 8.8.8.8 192.168.11.1 192.168.12,1; do  echo $dns ; time for i in {1..100}; do dig  +short @$dns t.co > /dev/null ; done ; done
1.1.1.1

real    0m2.012s
user    0m0.852s
sys 0m0.268s

8.8.8.8

real    0m1.851s
user    0m0.756s
sys 0m0.276s

192.168.11.1

real    0m0.845s
user    0m0.444s
sys 0m0.120s

192.168.12.1

real    0m0.587s
user    0m0.332s
sys 0m0.092s

なんか、public dns よりローカルのほうが速くね?

追記 DNSSEC の動作テスト

とくになにも設定してないけど、デフォルトで有効になってました。

takuya@:unbound$ dig +cd +short  @192.168.2.5 dnssec-failed.org
69.252.80.75
takuya@:unbound$ dig +short  @192.168.2.5 dnssec-failed.org
takuya@:unbound$ dig +dnssec +short  @192.168.2.5 dnssec-failed.org

参考資料