それマグで!

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

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

systemdのタイマーの実行予定・実行済を一覧表示する

systemd のタイマーの実行予定を俯瞰したい

crontab と違って systemdは個別ファイルに実行予定を記載するため、全体の予定がわからない。

それを一覧で俯瞰したいなと思ったときどうするのか

list-timersを使う

sudo systemctl list-timers --all

list-timersコマンドで、次回実行予定の一覧が閲覧できて便利である。

できればクリックしたいレベル。

実行サンプル

takuya@livaz:~$ sudo systemctl list-timers --all
NEXT                        LEFT          LAST                        PASSED        UNIT                         ACTIVATES
Tue 2022-04-19 14:23:22 JST 57min left    Tue 2022-04-19 08:02:50 JST 5h 23min ago  ua-timer.timer               ua-timer.service
Tue 2022-04-19 17:02:36 JST 3h 36min left Mon 2022-04-18 17:02:36 JST 20h ago       systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Tue 2022-04-19 18:52:52 JST 5h 26min left Tue 2022-04-19 08:04:55 JST 5h 21min ago  apt-daily.timer              apt-daily.service
Tue 2022-04-19 20:47:29 JST 7h left       Tue 2022-04-19 08:02:54 JST 5h 23min ago  fwupd-refresh.timer          fwupd-refresh.service
Wed 2022-04-20 00:00:00 JST 10h left      Tue 2022-04-19 00:00:06 JST 13h ago       logrotate.timer              logrotate.service
Wed 2022-04-20 00:00:00 JST 10h left      Tue 2022-04-19 00:00:06 JST 13h ago       man-db.timer                 man-db.service
Wed 2022-04-20 05:06:05 JST 15h left      Tue 2022-04-19 13:13:19 JST 12min ago     motd-news.timer              motd-news.service
Wed 2022-04-20 06:38:29 JST 17h left      Tue 2022-04-19 06:23:57 JST 7h ago        apt-daily-upgrade.timer      apt-daily-upgrade.service

参考資料

https://wiki.archlinux.org/title/Systemd/Timers

macのライブラリフォルダが見えないので見えるようにする。

ターミナルからコマンドで不可視を変えられる。

sudo chflag nohidden ~/Library
sudo chflag nohidden /Library

ただし、この方法でも ~/Library が見えないことがある。

Finder のオプションを使うのが確実。

nohiddenが動かない理由

sudo chflag nohidden ~/Library で動くはずなのだが、なぜか最新版のmacOSでは無効になっていた。

chflagでできないことが増えたのでmacosには一貫性が無いので本当に怖い。

タイムマシンで書き戻すのに必要

Libary をまるっと書き戻したいときにはFinderでLibaryを選択できないと書き戻せないので本当に勘弁してほしい。

過去記事

フォルダを不可視に設定する。または不可視フォルダLibraryを可視化する。 - それマグで!

三井住友銀行の通帳繰越は非対応のATMがある。(営業時間内に来店と表示された)

ATM通帳記入で窓口へとでた。

三井住友銀行のATMで通帳記入をしたんですよ。

そしたら、「この通帳はお取り扱いできません」って出るんですよね

15:00 までに銀行とか不可能じゃん。通帳繰越だけなんですよねぇ。

ATMを変えたら使えた。なんだそれ。

店舗を変えて違うタイプのATMにすると、通帳繰越ができて、通帳の切り替えができた。

f:id:takuya_1st:20220418142840j:plain

不親切なので、確認を

三井住友銀行は、とても不親切なので、ATMで通帳繰越が発生するときは、窓口へ行く前に、ATMを変えてみるといいと思います。

未だに旧住友銀行や旧さくら銀行のATMが稼働しているので、古いタイプのATMだとSMBCのATMでも通帳繰越ができないです。

とても不親切なので、店舗に行く前に確認を。

私は、店舗に行くと「ATMでできますよ」と言われ、「できへんから来とんやろ」という無駄なイライラを体験しました。問い詰めて、散々待たされて「非対応のATMはあります」と回答を得た。しんどかった。

グレーのATMではできない。白を探す。

旧ATMはだいたいグレーカラーです。新しいATMは白色ですね。

白色のATMなら通帳繰越ができるようです。殆どの場合店舗に併設されたATMですね。

出張所と書かれていると、「できない」と思ったらいいと思います。

WEB通帳は?

WEB通帳は信用していません。

割引があるといってもそのうち無くなるだろう。って言い続けてた。 昨年、本当になくなった。

WEB通帳は視認性も悪く、保管性も悪い。アプリ認証も煩雑。とても不親切なので、使う必要はないと思います。

WEB通帳に未加入でもインターネットから問題なく使えます。

wireguardでSNAT・マスカレードする

wireguard 経由のパケットをいい感じに転送したい。

wiregaurdのパケットをそのままLANに流すと、IPアドレスの経路がなくなって通信できなくなったりするので、Wireguardの出口側にNATを仕掛けてあげる必要がある。

そもそもWireguardはp2pだけを提供するので、その周辺は自分で面倒を見てあげないといけない感じです。 f:id:takuya_1st:20220418141334p:plain

マスカレードの例

WG_NET=172.16.41.0/24
LAN_IF=br0
LAN_NET=192.168.1.0/24
iptables -t nat -I POSTROUTING  -o $LAN_IF -s $WG_NET -d $LAN_NET  -j MASQUERADE

SNATの例

WG_NET=172.16.41.0/24
LAN_IF=br0
LAN_NET=192.168.1.0/24
LAN_IP=192.168.1.1
iptables -t nat -A POSTROUTING -d $LAN_NET  -s $WG_NET -j SNAT --to-source $LAN_IP

シェルスクリプトで変数と文字列を展開(置換)する

変数を文字列に展開するenvsubst

envsubst を使えば、文字列と変数を置換できる。つまり変数を展開できる。

利用サンプル

echo "HELLO \${HELLO}" | HELLO=takuya envsubst

テンプレートを作れる

これを利用すれば、テンプレートを作って文字列を作成するのが大変楽ちんになる。

CSVSQLのような文字列を埋め込むのが楽になるし、

変数を展開する変数を作って再帰的な処理をするのが大変楽になる。

参考資料

https://www.scriptlife.jp/contents/programming/2019/02/11/linxu-command-envsubst/

gRPC を使う

gRPC について

gRPC はリモートからデータ取得、データ変更するRPCの一種

google が作って、http/2 とうまく協調するようにしている

一言でいえば、C構造体をそのままぶん投げるプロトコル

サーバーとクライアントが事前にお互いに構造を知っていれば、JSONみたいに配列にしたり、オブジェクトキーを入れなくていいよね。

乱暴に言えば、sqlite3 で1行転送してるようなもん。お互いテーブル構造を知ってれば問題ないでしょ?みたいな感じ。

準備する

├── proto
│   └── user.proto
├── protos
│   └── user.proto
├── py
│   ├── Pipfile
│   ├── Pipfile.lock
│   ├── client.py
│   ├── server.py
│   ├── user_pb2.py
│   └── user_pb2_grpc.py
└── users.json

python を準備する

PIPENV_VENV_IN_PROJECT=1 pipenv install
pipenv run pip install 
pipenv run pip3 install grpcio grpcio-tools

protoを作る

protoを作る。データベースでいうスキーマC言語でいう構造体。

proto が特徴的なのは、次の3点だと感じた。

  • protoに名前空間がある
  • proto はメソッド定義を含む
  • proto は 自身にprotoを使った参照(再帰)定義ができる

JAVAのクラス定義だとメンバとメソッド雛形が分けづらい

Cの構造体だと名前空間が使えない。

データベースのスキーマだと参照定義ができない

JSONだと冗長になりすぎる

という部分が解消されて使いやすい「データ型の定義」だと感じた。

SQLiteをリモート転送するには便利そうですよね。

server.py

自動生成されたクラスを継承して作る

client.py

自動生成されたクラスを呼び出して使う。

リクエスト実験

サーバー起動

pipenv run python server.py

クライアント側

pipenv run python client.py 1
pipenv run python client.py 2
pipenv run python client.py 3
pipenv run python client.py 10

grpcurl でリクエストを送る

grpcurl -plaintext -import-path ../protos -proto user.proto  -d ' { "id": 1 } ' localhost:1234 UserManager.get
{
  "user": {
    "id": 1,
    "nickname": "admin",
    "mailAddress": "admin@example.com",
    "userType": "ADMINISTRATOR"
  }
}

http2

http2 らしいのでtcpdump でパケットを見てみる。

f:id:takuya_1st:20220418140344p:plain

f:id:takuya_1st:20220418140414p:plain

cURLで叩きたい

HTTP/2 なので、cURLで叩けそうですが。絶対めんどくさい。

バイナリ転送が基本。まるでC構造体のようなProtoのまま転送しているので、中身を見ても仕方ないし、手動でリクエストを送るのも手間である。

どうしてもやりたきゃ、プロキシする必要がありそうです。

っていうか、冗長性を排してバイナリ転送するのがgRPCだし

参考資料

サービス間通信のための新技術「gRPC」入門 | さくらのナレッジ

https://engineering.mercari.com/blog/entry/2019-05-24-120000/

qcow2 のsparse ファイルのサイズをトリム(節約)- reclaim

qcow2 のファイルが肥大化することがある。

使ってないファイルは消え、ディスク容量を浪費しないはず。だが、実際には、一度確保したファイルを削除しても容量が消えない。なので、長期間メンテナンスなしで使ってるとファイルサイズが肥大化してた。なんとか節約してきれいにすることはできないのかな。

reclaim する方法

容量を取り戻すには、ファイルをコピーして作り直せばいい

qemu-img convert -O qcow2 image.qcow2 shrinked_image.qcow2

ついでに圧縮する

圧縮をかけておけば、変わらない部分に関しては容量を節約できるはず。 -c をつけて圧縮

qemu-img convert -c -O qcow2 image.qcow2 shrinked_image.qcow2

2022-09-21 追記

virt-sparsify でも同じことが出来る。virt-sparsifyのほうが時間がかかるが、出来上がりはきれいに容量が減っている。

参考資料

Reclaim empty space from, Shrink disk of qcow2 disk file – note to self

qcow2 のストレージを直接マウントする。(ループバックで接続経由し、losetupで使う。)

qcow2 ディスクイメージをマウントしようと思ったら、loop back で接続すればいいとわかった。

raw であれば、losetup -P -f /path/to/raw.imgでlosetupで手軽に扱えるが、qcow2の場合は、nbdを経由する。

qcow2 のディスクを接続する

コネクトを使う。

sudo modprobe nbd max_part=8
sudo qemu-nbd --connect=/dev/nbd0 /var/lib/libvirt/images/d02.qcow2
sudo fdisk /dev/nbd0 -l
sudo qemu-nbd -d /dev/nbd0 

nbd 機能を使えば、qcow2 をループバック接続できて、フォーマットやインストール、状況を見ることができる。これを使えば通常のストレージのファイルと同じように扱える。

/dev/nbd0 ループバック・マウント後

ループバックさえできれば、あとはmount したり gdisk したりできるよね。

mount /dev/nbd0p2  /mnt

ただし、qcow2 は完全なディスクイメージなので、lvm になってたり、dm-cryptがかかってたりするので、/dev/mapper経由でマウントすることになる可能性が高い。

mount /dev/mapper/xxx-root-vg /mnt

nbd 機能の有効無効の切り替え

Failed to open /dev/nbd0: No such file or directory のようにnbd が存在しないエラーになるときは、カーネル拡張をロードしてやればいい

sudo modprobe nbd max_part=8

使い終わったら アンロードしておけばいい

sudo rmmod nbd

LVMを含むqcow2 のnbd は注意が必要

lvm を含む nbd を扱うと、nbd デバイスをロードした瞬間に lvm が走って、lvm として認識されちゃう。

認識されちゃうと、nbd を切断しても lvm に残ってしまう。

takuya@:~$ sudo qemu-nbd --disconnect /dev/nbd0
/dev/nbd0 disconnected
takuya@:~$ sudo partprobe
Warning: Error fsyncing/closing /dev/mapper/d01--vg-root: 入力/出力エラーです
Warning: Error fsyncing/closing /dev/mapper/d01--vg-swap_1: 入力/出力エラーです
Warning: Error fsyncing/closing /dev/nbd0p1: 入力/出力エラーです
Warning: Error fsyncing/closing /dev/nbd0p2: 入力/出力エラーです
Warning: Error fsyncing/closing /dev/nbd0p3: 入力/出力エラーです

lvm を含むディスクを扱うときは、手作業でLVMから取り外すしか無いです。

認識されちゃったときは手動で、INACTIVEにしておくと無難

vgchange -an  qcow_vg

マウントして調べるときは/boot 型違反だと思うので、ほぼ使わないので、自動化しないでほしいところ

lvm が消えないとき

lvm, が消えない、そのときは、dmsetpup をた試すのもいい。

sudo dmsetup ls 
sudo dmsetup removevg-lv05

dmsetup をしたあとに再度、除去を試す。

sudo qemu-nbd -d /dev/nbd0 
sudo rmmod nbd

これでも駄目なら再起動するしか・・・・

参考資料

https://consolechars.wordpress.com/2015/07/15/how-to-qcow2-files-mount-in-yours-linux-system-with-lvm/

https://bbs.archlinux.org/viewtopic.php?id=264163

kvm-qemu/virsh でクローンの作成

KVM/QEMU仮想マシンを別のマシンへコピーしたい

マイグレーションだと「移転・移動」してしまうので、「コピーして移動したい」

全体の流れ

という2段階でやろうと思う。

コピー/クローンの作成について

クローン作成コマンド

クローン作成には、virt-clone を使うと楽

virt-clone --original AdguardHome --name AdguardHome02 --auto-clone

virt-clone の準備

virt-clone コマンドは、virsh とは別のパッケージなため未導入の場合がある。

sudo apt install virtinst

未停止の場合

clone にはシャットダウンが要求されるためシャットダウンしておく

virsh shutdown xxx

シャットダウンしてないとエラーになる。

$ virt-clone --original AdguardHome --name AdguardHome02 --auto-clone
ERROR    Domain with devices to clone must be paused or shutoff.

clone 時の注意

クローンは、丸コピーとは違ってクローン作成です。同じものを「起動できる状態」にしてくれる

何を言ってるのかというと、MACアドレスは変わる。MACアドレスが変わるということは ubuntu など cloud-init でnetplanしているとMACが変わってIP割当が変わる。

コピーの確認

シャットダウン状態でコピーされるので、

virsh list --all 

または、virt-managerから

必要な時間

qcow2 などボリュームをコピーするので、SSDの書き込み速度とqcow2 の容量に依存する。8GB で5分程度かかった

できないこと

clone 時に、SSH経由でCloneができればよかったんだけど

一気呵成にできない。

virt-clone \
   --original qemu:///system/FromVM  \
   --name qemu+ssh://takuya@another/system/ToVM` 

のようなURI+パスで仮想マシン指定でができれば強かったんだけど。できないですね。

マイグレーション

移転の方法は、2つある。

今回は、rsync 移転にする。

手作業転送とライブマイグレーション

ライブマイグレーション機能はストレージを共有しているホスト間で仮想マシンを移動することが前提だったと思う。

ライブマイグレーションは、「ストレージを共有しているホスト間でメモリや書き込みを転送しつつ」うまい感じに起動したままホストを移動する機能なので、オフラインで転送するようなコピーには全く向かない。

設定を取り出して転送

dumpxml で取り出して ssh 経由でサクッと転送。

virsh dumpxml DomA | ssh srv02  dd of=DomA.xml

設定をロード

virsh define DomA.xml

XML ファイル名がドメイン名(仮想ゲスト名)になる。

ストレージを転送

ストレージを転送

rsync -avz --progress --partial DomA-clone.qcow2 takuya@srv02:~

起動する

最後に起動しして終了

ssh srv02 virsh start DomA

sslh で 443 ポートのUDP/TCP を振り分ける(openvpn/udpとwireguard/ udp を使う)

443 ポートを活用する

443 ポートで https / ssh / openvpn / wireguard を全部の待受ができたらいいなと思った。

フリーWiFiが443 / 53 /80 以外のポートを使わせてくれない事が非常に多い。公衆無線LANでポート監視やるのは流石にまずいと思うんだけど。実際やられてるんだから仕方ない。あまり監視をしちゃうと、某国みたいにVPNのイタチごっこが始まるので本当に勘弁してほしい。

よろしい、ならば抵抗してみよう。

sslh 最新版が UDP に対応

sslh の最新版(1.22)がUDPに対応していた

最新版コードを持ってきて ビルドする

git clone https://github.com/yrutschle/sslh.git
cd sslh
make 

UDP にも対応させる

UDPはfork でパケットを流せないらしいので、select コールで使うらしい

./sslh-select -F /etc/sslh.conf

/etc/sslh.conf

verbose: 0;
foreground: true;
inetd: false;
numeric: false;
transparent: true;
timeout: 1;
user: "sslh";
pidfile: "/var/run/sslh/sslh-select.pid";



# Change hostname with your external address name.
listen:
(
    {
      host: "192.168.1.222";
      is_udp: false;
      port: "443";
    },
    {
      host: "192.168.1.222";
      is_udp: true;
      port: "443";
    }
);

protocols:
(
    { name: "ssh";
          service: "ssh";
          host: "127.0.0.1";
          port: "8022";
          is_udp: false;
          fork: true;
    },
    { name: "openvpn"; host: "localhost"; port: "1194"; },
    { name: "tls";
        host: "127.0.0.1";
        port: "443";
        alpn_protocols: [ "h2", "http/1.1", "spdy/1", "spdy/2", "spdy/3" ];
        is_udp: false;
        fork: true;
        log_level: 0;
        tfo_ok: true },
    # wireguard
    { name: "regex";
        host: "192.168.1.21";
        log_level: 2;
        is_udp: true;
        fork: false;
        port: "11945";
        regex_patterns: [ "\x01\x00\x00\x00" ];
      }
);

wiregaurd は regex

regex_patterns: [ "\x01\x00\x00\x00" ];

これで、wireguardのパケットを識別できるらしい。識別できるってことはブロックされちゃうってことでもあるけど、そこまで流行ってないwireguardだ、これでしばらく通信できそうな気はする。

UDPTCP を同時リッスンするポイント

リッスンをudp/tcp と2つかくことが設定ポイントになる。

listen:
(
    {
      host: "192.168.1.222";
      is_udp: false;
      port: "443";
    },
    {
      host: "192.168.1.222";
      is_udp: true;
      port: "443";
    }
);

UDP サポートについて

UDPは本家のマニュアルに記載が追加されていた。

https://github.com/yrutschle/sslh/blob/master/doc/config.md#udp

UDPがサポートされたのは2021/08 の 1.22 リリース前後のようです。

443 ポートで隠す?

暗号化通信をしていたとしても、SNIでドメイン名は丸見えだし、IPアドレスは隠せない。

そうなると、必然的にVPNを使うことになる。TLSでトンネルを掘るとか、HTTPSで Proxy Connectをすることになる。

となると、TLS通信を監視する必要が出てくる。そのためにカスペルスキーのようなソフトでTLSの監視を行うことになる。

となると、すべての通信はLocalhost経由になり、監視されることになり、証明書を信用できなくなる。本当にそれは望んだ自由な社会なのだろうか。

IPv6でIP範囲指定が難しくなり、すべての端末がグローバルアドレスになりつつある現代でローカルネットやPC管理を前提としたセキュリティは崩壊寸前かもしれない。

IPv6 での rsync のIPアドレス指定

v6 の場合、rsyncIPアドレス指定はめんどくさい

rsync -avz sample.xml 'takuya@[2001::1:34]:~'

ポイント

v6 アドレスは[ ] で 囲む

rsync -avz sample.xml takuya@[2001::1:34]:~

[ ]bash に解釈されるので、クォートする

rsync -avz sample.xml 'takuya@[2001::1:34]:~'

めんどくさい。。。

Explorer で Sambaを見るとファイル名がチルダの文字になる

チルダの文字なる

Samba経由でLinuxのファイルを見ると、英数文字で5文字、チルダ、英数字のファイルになる。

再現方法

次のようなファイルを作ると、再現できる。

touch aaaa?

原因

Linuxのファイル文字とWindowsの使用禁止文字が異なるためらしい。

対応

Windowsで禁止されているファイル文字を使わないようにする

化ける文字

次の文字が化ける。

> : " / \ | ? * < 

クエスチョンマーク

! は問題ないが、?マークで化けるので ? を何とかする

たとえば、!?と連続して使われる場合、!?の代わりに絵文字の⁉を使うとか。

rename 's/!\?/⁉/g'

単体の? は全角に変換しておけばいいでしょう。

rename 's/\?/?/g'

!? のように使われると全角にすると読みにくくなる。なので、⁉の絵文字を使った。

よくあるパターン

* アスタリスクが化ける。

アスタリスクなんて使わないと思うんだけど、コマンド入力ミスでファイルが作られてしまったりする。

rename 's/\*/\*/g'

... ピリオドの三点リーダ

ファイル名に ... があると化ける。三点リーダーにする

再現方法

mkdir aa....

対症方法

rename 's/.\.\.\/\…/g'

その他に、ピリオドが原因で起きるもの

調べてみると、末尾に、3つ以上で表示がおかしくなりました。

touch い.  # 表示可
touch ああ.. # 表示可
touch ううう...      # 起きる
touch ええええ....  # 起きる
touch お...おおお  # 表示可

bbb \aaa 末尾の空白

ファイル名の末尾に空白があると化けます。

再現方法

touch 'Xaaa '
rename 's/ +$//' 

末尾の空白は、1つ以上でダメです。複数スペースもダメです。

全角のスペースは使えます。

"!?"と続けた場合

これは!?.txt # 化ける
これは⁉.txt # 化けない

このことから ! ? が続けてて使われている場合は、 のマルチバイト文字に置換したほうがいいかと思います。

Sambaのファイル名に注意する必要がある。

Sambaでファイルを扱うとどうしてもこういう細かい部分で苦労する。

ファイル名に...!? なんか使うか?と思うんだけど調べたら結構ありました。

作りかけのファイルだったり、ファイル名でコミュニケーションをしている使い方をしてる企業様や、WEBページをHTML保存したときに発生しますね。

スクレーパー掛けたときにファイル名をWebページのtitle にしている場合なんかも起きますね。

参考資料

SMB経由でアクセスすると、ファイルまたはフォルダの名前が12HWA0〜8のように表示されます。どうすればいいですか? - Synology ナレッジセンター

ChromeのHSTS( http → httpsリダイレクト)の記憶を消す

chrome のHSTSが邪魔

443/ 80 の https のリダイレクトを設定しているとブラウザが学習したリダイレクトが邪魔になる。

HSTSを学習するなとは言わないが、クライアント側で完結されるのは邪魔である。リダイレクトの期限をつけて制御したいところである。 しかし学習ししてしまったら消すしか無い。

hsts の設定画面から消す。

chrome://net-internals/#hsts

f:id:takuya_1st:20220411154741p:plain

chrome履歴画面の検索結果を全部クリックする(shadowroot経由のDOM JS)

特定の検索結果の履歴を全部消したい

Googleの閲覧履歴を検索して消したい。消したいけど、「すべて消す」が無い。

検索結果をすべて選択がない。

すべて選択がないので、ちまちま消す必要があるだるすぎる。

Devtoolでまとめてチェックしたい

ボタンがないならDevtoolでアクセスだ。ぜんぶチェックしてやる。

React?Angular?かなshadowRootがある。

id=history-app に下に shadow-root(open) がある。このままでは css セレクタでアクセスできない。

ShadowRootへアクセスするには

エレメントに shadowRootが生えている。これを使う。コンテキストを切り替えて要素をたどってしまえば、強引にクリックできる。この手はSeleniumなどでも使える。まぁ通常はスクリーンの指定領域にClickイベントを送るだろうけど、直接要素を触ることも出る。

const e = document.querySelector('#some-app')
SomeRoot = e.shadowRoot
SomeRoot.querySelector(' div ')
div.click()

履歴の検索結果をぜんぶクリックする。

Chrome のコンソールを使ってつぎのようにする。

appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
for ( e of historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') ){
  e.shadowRoot.querySelector('cr-checkbox#checkbox.no-label').click()
}

コンソールに貼り付けて

実行

一気に選択できた。

仕組み

冒頭で書いた通り、shadowRootを辿っていく。

historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') でアイテムを探している

アイテムをクリックする。

#shadowRootに入っていく
appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
itemRoot =  historyRoot.querySelectorAll('iron-list history-item')[10].shadowRoot # index=10 
# 該当のアイテムをクリック
itemRoot.querySelector('cr-checkbox#checkbox.no-label').click()

表示中のアイテムを全部クリックする。

appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
for ( e of historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') ){
  e.shadowRoot.querySelector('cr-checkbox#checkbox.no-label').click()
}

削除ボタンを押す場合

appRoot = $('#history-app').shadowRoot
toolbar = appRoot.querySelector('#toolbar').shadowRoot
selectionOverlay = toolbar.querySelector('cr-toolbar-selection-overlay').shadowRoot
selectionOverlay.querySelector("#delete").click()

ダイアログボックスを押す場合

appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#content history-list').shadowRoot
historyRoot.querySelector('cr-dialog cr-button:nth-child(2)').click()

表示中のアイテムをすべて削除(コピペ用)

(async function delete_displayed(){
  async function select_displayed(){
    appRoot = $('#history-app').shadowRoot
    historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
    for ( e of historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') ){
      e.shadowRoot.querySelector('cr-checkbox#checkbox.no-label').click()
    }  
  }
  async function click_delete(){
    appRoot = $('#history-app').shadowRoot
    toolbar = appRoot.querySelector('#toolbar').shadowRoot
    selectionOverlay = toolbar.querySelector('cr-toolbar-selection-overlay').shadowRoot
    selectionOverlay.querySelector("#delete").click()
  
  }

  async function click_confirm(){
    appRoot = $('#history-app').shadowRoot
    historyRoot = appRoot.querySelector('#content history-list').shadowRoot
    historyRoot.querySelector('cr-dialog cr-button:nth-child(2)').click()  
  }
  await select_displayed();
  await click_delete();
  await click_confirm();
  
})();

インフィニット・ロード

無限ロードなので、スクロールバーが最下部まで行かないと、次がロードされないんので、全部選択したつもりでも残ることはある。

非表示もクリックしてしまう。

ざっと書いただけなので、非表示になってるAppもクリックしてしまうので、エラーになることがある。

async をする必要がある。

shadowrootへのアクセス方法

Shadowrootへの強引なアクセス方法を覚えておくと、一番低レイヤなので、Seleniumなどでスクレーピングするときに使えそう。

Chromeは履歴を消させたくない?

履歴の絞り込みで一気に消したいときなのに、すべて選択がない。

履歴の絞り込みができるのに、マッチ結果をすべて削除が機能にない。

マッチ結果を削除がないのは致命的な欠陥である、Vivaldiなど別のブラウザでは簡単にできるのだが。

ほかブラウザでは可能なのに、Chrome だけが履歴削除について機能を制限している。

これは、アクセス履歴を「何らかの広告」にいや「個人の追跡」に使っている傍証ではないかと想像する。やはり、Googleは組織として邪悪になってるのかなと信用を置けない。

2022/09/10

HTMLの構造が若干変わってたので記述内容を変更

ブラウザでSSHを接続する webssh

ブラウザのHTMLでSSHする

webssh を使うと、ブラウザの中でSSH接続ができる。

ブラウザの中でSSHをサービスとして提供できるようになる。

使用例

f:id:takuya_1st:20220408161035p:plain

接続概要

ブラウザはWebSocketを喋る。

ブラウザ--[websocket]-->webssh

リモートのサーバからは、SSHで出ていく。

webssh -- [ssh] -- > ssh server

接続の概要を見たらわかる通り、Linuxサーバーを踏み台にしてSSHするのと同等である。

インストール

pipenv を使ってインストールすることにする。

mkdir webssh
pipenv 
pipenv shell 
pip install webssh 
webssh

起動

ポート指定・アドレスしてリッスンする。

## または 全部指定
wssh 
## 指定
wssh --port=5571 --address=127.0.0.1

使い所

SSHクライアントのインストールが制限されているような環境でも接続が可能になる。

ただ、この目的であれば、Chrome拡張機能で直接SSHを喋るのでChrome拡張機能が望ましいと思う。

踏み台を用意するのがめんどくさい、SSLで抜けてSSHを接続したいときに使えそうですよね。

nginx にインストール

ssl はnginx で管理したほうが楽

nignx の設定例

server {

  listen 127.0.0.1:443 ;
  server_name _;
  server_tokens off;
  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Real-PORT $remote_port;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_connect_timeout 300;
    # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    chunked_transfer_encoding off;
    proxy_pass http://127.0.0.1:5571/;
  }

}

nginx のサブディレクト

複数の接続を切り替えて使うなら、サブディレクトリを使うほうが楽だと思う。

location / { location /terminal/ { に切り替える。

server {

  listen 127.0.0.1:443 ;
  server_name _;
  server_tokens off;


  location /terminal/ {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Real-PORT $remote_port;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_connect_timeout 300;
    # Default is HTTP/1, keepalive is only enabled in HTTP/1.1
    proxy_http_version 1.1;
    proxy_set_header Connection "";
    chunked_transfer_encoding off;
    proxy_pass http://127.0.0.1:5571/;
  }

}

プロキシ先にも注意

proxy_pass http://127.0.0.1:5571/; にすることがポイント

proxy_pass http://127.0.0.1:5571; だとディレクトリも含めてバックエンドに送られる。

開いた瞬間に接続

開いた瞬間に接続させることもできる。

https://127.0.0.1/terminal/?hostname=192.168.1.1&username=takuya&password=XXX

参考資料

https://github.com/huashengdun/webssh