それマグで!

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

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

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

参考資料

gitbookのビルドだけをgulpでフォルダ監視して自動実行したい

gitbook-cli でサーバーがいちいち上がるのがめんどくさい。

gitbook を使い込む気は、あまりないのだけど、マークダウンを記述して、gitbook serve で 変換が必要

gulp で監視してしまいたい。

HTMLに変換するだけなら、べつにserve は要らないし、そこまでリアルタイムな編集も要らないんだよね。

gitbook watch がほしいとおもったけど見つからないので、 しかし、gitbook-cli は開発終わってる。

仕方ないので、gitbook watch 代わりにgulp watch を作ってみた。

gitbook はWEBサービスになっちゃったんだけど、なんか残念だよね。

gitbook-cli のビルド部分だけを gulp 化したもの

var gulp = require("gulp");


gulp.task('watch', function(done){

  gulp.watch(['**/*.md'], gulp.task('book'));

});


gulp.task('book', function( done ){
  // ./node_modules/.bin/gitbook から抜粋
  var parsedArgv = require('optimist').argv;
  var color = require('bash-color');
  var manager = require('./node_modules/gitbook-cli/lib');
  var commands = require('./node_modules/gitbook-cli/lib/commands');
  var program = require('commander');
  var bookRoot = parsedArgv._[1] || process.cwd();

  function runPromise(p) {
    return p
      .then(function() {
        process.exit(0);
      }, function(err) {
        console.log('');
        console.log(color.red(err.toString()));
        if (program.debug || process.env.DEBUG) console.log(err.stack || '');
        process.exit(1);
      });
  }
  return manager.ensureAndLoad(bookRoot,program.gitbook)
    .then(function ( gitbook ) {
      return commands.exec(gitbook.commands, 'build', [], [])
    });
});

ハードウェアの情報を一覧する lshw コマンド

ハードウェアの情報を収集して出力する

lsusb や lspci などのコマンドがあるけど、まとめて実行して情報を取り出すには不便。調べたら lshw といういうコマンドを見つけた

インストール

takuya@:~$ sudo apt search lshw
ソート中... 完了
全文検索... 完了
lshw/stable 02.18-0.1 amd64
  ハードウェア設定に関する情報

lshw-gtk/stable 02.18-0.1 amd64
  ハードウェア構成に関する情報をグラフィカルに表示

python3-checkbox-support/stable 0.22-1 all
  collection of Python modules used by PlainBox providers

takuya@:~$ sudo apt instal  lshw

使い方

sudo をつけてコマンドを実行すると良い。 htmlやXMLで取得することも可能だ。

takuya@:~$ sudo lshw -h
Hardware Lister (lshw) - unknown
usage: lshw [-format] [-options ...]
       lshw -version

    -version        print program version (unknown)

format can be
    -html           output hardware tree as HTML
    -xml            output hardware tree as XML
    -short          output hardware paths
    -businfo        output bus information

options can be
    -class CLASS    only show a certain class of hardware
    -C CLASS        same as '-class CLASS'
    -c CLASS        same as '-class CLASS'
    -disable TEST   disable a test (like pci, isapnp, cpuid, etc. )
    -enable TEST    enable a test (like pci, isapnp, cpuid, etc. )
    -quiet          don't display status
    -sanitize       sanitize output (remove sensitive information like serial numbers, etc.)
    -numeric        output numeric IDs (for PCI, USB, etc.)
    -notime         exclude volatile attributes (timestamps) from output

実行例

そのまま実行すると出力が大きすぎなので、ターミナルで実行するときは -short オプションがおすすめ

takuya@:~$ sudo lshw  -short
H/W path         デバイス     クラス      詳細
=======================================================
                                  system         To Be Filled By O.E.M. (To Be Filled By O.E.M.)
/0                                bus            J5005-ITX
/0/0                              memory         64KiB BIOS
/0/b                              memory         8GiB システムメモリー
/0/b/0                            memory         8GiB SODIMM DDR4 同期 2400 MHz (0.4 ns)
/0/b/1                            memory         DIMM DDR2 同期 [空]
/0/15                             memory         224KiB L1 キャッシュ
/0/16                             memory         4MiB L2 キャッシュ
/0/17                             processor      Intel(R) Pentium(R) Silver J5005 CPU @ 1.50GHz
/0/100                            bridge         Intel Corporation
/0/100/0.1                        generic        Intel Corporation
/0/100/2                          display        Intel Corporation
/0/100/e                          multimedia     Intel Corporation
/0/100/f                          communication  Intel Corporation
/0/100/12                         storage        Intel Corporation
/0/100/13                         bridge         Intel Corporation
/0/100/13.1                       bridge         Intel Corporation
/0/100/13.2                       bridge         Intel Corporation
/0/100/13.2/0    enp3s0           network        RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
/0/100/13.3                       bridge         Intel Corporation
/0/100/13.3/0                     storage        ASM1062 Serial ATA Controller
/0/100/15                         bus            Intel Corporation
/0/100/15/0      usb1             bus            xHCI Host Controller
/0/100/15/0/3                     generic        802.11n WLAN Adapter
/0/100/15/0/5                     communication  BT2.0
/0/100/15/0/6                     bus            NEC USB HUB (ASC)
/0/100/15/0/6/1                   input          109 JPN USB KBD (ASC)
/0/100/15/0/6/3                   input          wireless dongle
/0/100/15/1      usb2             bus            xHCI Host Controller
/0/100/1f                         bridge         Intel Corporation
/0/100/1f.1                       bus            Intel Corporation
/0/1             scsi0            storage        
/0/1/0.0.0       /dev/sda         disk           240GB ADATA SP550
/0/1/0.0.0/1     /dev/sda1        volume         511MiB Windows FAT ボリューム
/0/1/0.0.0/2     /dev/sda2        volume         732MiB EXT4ボリューム
/0/1/0.0.0/3     /dev/sda3        volume         48GiB EFI partition
/0/1/0.0.0/4     /dev/sda4        volume         174GiB EXT4ボリューム
/1               vlan2            network        イーサネット interface
/2               vlan10           network        イーサネット interface
/3               vlan200          network        イーサネット interface
/4               vlan30           network        イーサネット interface
/5               wlx000b8181dc8e  network        無線インターフェース
takuya@:~$ 

if 文には必ずブロックをつけろと言われることが多いけど、使い方によってはむしろ邪魔

if にブロックがないと叱られたことが昔から多い。

if のブロックって上手に書けばいいと思うし、設定やLintで矯正されたりするんだけどさ。

この if の書き方を見ほしい

function setupAce(e, set){
  
  //デフォルト設定(カスタマイズしたい場合はの引数(set)に以下の様にセットして下さい。)
  if(!set) set = {
    theme:"chrome",  
    mode:"text",    
    options:{        //AceEditorOption設定類
      fontSize: "12px",
      maxLines: 30,
      minLines: 5,
      showInvisibles: true,
    },
    focus:false
  };

一見するとブロックがあるように見えるけど、ブロックは使ってなくて、初期化変数。

なかなかおもしろいよね。工夫次第でシンプルにわかりやすく記述はできるんだなと

laravel の api ルートを叩いてもloginページやHTMLが帰ってきてjson以外になってしまう場合

TL;DR

HTTPリクエストのヘッダに、 Accept: text/json が抜けている可能性が高い。

Laravelのレスポンスが login になる場合。

api で auth を入れているところへリクエスト投げつける。

HTMLのログインが帰ってくる。

実例

curl -H 'Content-Type: application/json' -F file='@/Users/takuya/Pictures/Dh6PcyQUYAEzhKp.jpg' http://127.0.0.1:8000/api/user/1/images/ 

* Connected to 127.0.0.1 (127.0.0.1) port 8000 (#0)
> POST /api/user/1/images/ HTTP/1.1
> Host: 127.0.0.1:8000
> Accept: */*
> Accept-Encoding: gzip, deflate, sdch
> User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.76 Safari/537.36
> X-Config-File: ~/.curlrc
> Content-Length: 37112
> Content-Type: application/json; boundary=------------------------f7fa3a50954906f3
> Expect: 100-continue
>
* Done waiting for 100-continue
  0 37112    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0} [37112 bytes data]
* We are completely uploaded and fine
< HTTP/1.1 302 Found
< Host: 127.0.0.1:8000
< Date: Tue, 28 May 2019 14:57:15 +0000
< Connection: close
< X-Powered-By: PHP/7.3.4
< Cache-Control: no-cache, private
< Date: Tue, 28 May 2019 14:57:15 GMT
< Location: http://127.0.0.1:8000/login
< X-RateLimit-Limit: 60
< X-RateLimit-Remaining: 59
< Content-Type: text/html; charset=UTF-8
<
{ [352 bytes data]
100 37464    0   352  100 37112    272  28724  0:00:01  0:00:01 --:--:-- 28996
* Closing connection 0
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="refresh" content="0;url=http://127.0.0.1:8000/login" />

        <title>Redirecting to http://127.0.0.1:8000/login</title>
    </head>
    <body>
        Redirecting to <a href="http://127.0.0.1:8000/login">http://127.0.0.1:8000/login</a>.

同一ページに Accept-JSONを併せて送りつけた場合。

HTTPのヘッダにAcceptを入れると、401 がとJSONが返ってくる。

takuya@$ curl-json -H 'Content-Type: application/json' -F file='@/Users/takuya/Pictures/Dh6PcyQUYAEzhKp.jpg' http://127.0.0.1:8000/api/user/1/images/ 

> POST /api/user/1/images/ HTTP/1.1
> Host: 127.0.0.1:8000
> User-Agent: curl/7.65.0-DEV
> Accept: text/json
> X-Config-File: ~/.curlrc-json
> Content-Length: 37112
> Content-Type: text/json; boundary=------------------------4610ff915435cd7f
> Expect: 100-continue
>
* Done waiting for 100-continue
} [37112 bytes data]
* We are completely uploaded and fine
< HTTP/1.1 401 Unauthorized
< Host: 127.0.0.1:8000
< Date: Tue, 28 May 2019 14:54:59 +0000
< Connection: close
< X-Powered-By: PHP/7.3.4
< Cache-Control: no-cache, private
< Date: Tue, 28 May 2019 14:54:59 GMT
< Content-Type: application/json
< X-RateLimit-Limit: 60
< X-RateLimit-Remaining: 58
<
{ [30 bytes data]
* Closing connection 0
{"message":"Unauthenticated."}

laravel のAPIにリクエストを送付するときは

リクエストヘッダのAccept(クライアントが受け取りたいMIME形式の指定)でJSONを指定する必要がある。

Accept: text/json

これは、どこで定義されているのか

Accept をみてMIMEや認証は、どこのメソッドで定義されているのか。

vendor/laravel/framework/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php#expectsJson
<?php
public function expectsJson()
    {
        return ($this->ajax() && ! $this->pjax() && $this->acceptsAnyContentType()) || $this->wantsJson();
    }

ここでリクエストのヘッダを見ている。HTTP/Requestで使える。

参考資料

https://github.com/laravel/framework/blob/5.8//src/Illuminate/Http/Concerns/InteractsWithContentTypes.php#L42

composer でgithub / gitlab などのgit レポジトリをコマンドから指定してインストール

php/composer でコマンドから git レポジトリをインストールしたい。

composer で git のレポジトリ(非公式 package / 自作pkg )を指定して追加して使いたい。

通常は composer.json を編集するのだろうけど、 jsonの手作業の編集は、苦痛。

なので、コマンドから指定して実行したら楽になる。

手順

  • composer.json に config を追加
  • composer install

composer.jsonに git(vcs)を追加する。

composer config コマンドを使って、git でアクセス可能なレポジトリを追加します。

composer  config repositories.my-helpers vcs ssh://git@example.com/takuya/my-helpers.git

これで、json ファイルができた。

composer install します。

vcs を参照するようになったら、require に登録してインストールします。

composer require --dev  takuya/my-helpers:master
composer install

レポジトリ名はURLから github.com/takuya/my-repos のような構造からパスを取り出して、ブランチを指定する。

これでミスなく手軽になる。composer で自作の非公開のパッケージを自動的に取り込む構成が作れるので、dockerイメージや docker-compose でインストールのスクリプトを作るときなどに本当に楽になる。

関連資料

http://takuya-1st.hatenablog.jp/entry/2014/07/09/114736

参考資料

https://stackoverflow.com/questions/31743139/how-to-add-non-public-repositories-from-command-line-with-composer

JS で String#replaceAll すべて置換をするには

JS のコードレビューをしていて、気になってしょうがない split.join

いっぱい次のような、関数をいっぱい見かけるのですが、これは replaceAll の代りにし使ってるんだろうか。一般的なんだろうか。 どっかのサイトで上位に出てくるんだろうか。○iita とか

## これはやめてほしい。
update_date.split('-').join('');

正規表現で意図が明確コードを

正規表現のグローバルマッチを使うと良い。

update_date.replace( /-/g , '' );

置換はコールバックが便利

置換するなら、コールバックをすることが便利。

update_date.replace( /-/g ,  function( e ){   return e+'--'   } );