JavaScript で TOTP を計算する

TOTP: Time-Based One-Time Password Algorithm とは、二要素認証でよく見る Google Authenticator 等で QRコード を読み込ませたりして、一定時間毎に替わる 6桁 くらいの数字を入力するアレだ。

RFC 6238 に詳しい仕様が書かれている。
コイツを TOTP をブラウザ上で生成したい。

幸い近年の Web API には、バイナリ操作やクリプトまわりの機能が出揃っているので、わりかし簡単に実装できそうだ。
…とまぁ、そんな愚生が思いつくような話など既に、偉大なる先人たちによる多くのサンプルが残されている。

せっかく自分で実装するなら、最新の ES 仕様や Web API を活用して簡潔に、それでいて汎用的な仕様で書いてみよう。

実装

続きを読む

D&DしたQRコード画像をブラウザ上でデコードする

ブラウザ上にドラッグ&ドロップ (D&D) されたQRコードの画像を、読み込んでデコードするUIを作りたい。

Pure JavaScript で動作する、QR コードデコーダー(パーサー) cozmo/jsQR が有名なので、これを使ってみよう。

jsQR は、 png や jpg といった画像コンテナの解凍機能も、 HTML や DOM, Web 周りに特化した機能も一切無いため、読み込ませた画像は何らかの方法で Uint8ClampedArray な RAW 画像に変換して渡す必要がある。

ちょっと遠回りにはなるが、

  1. D&D されたファイルの File API を読み取る
  2. FileReader API を使って、ファイルを DataURI として読み込ませ、 img タグに表示させる
  3. OffscreenCanvasOffscreenCanvasRenderingContext2D を経由して ImageData を作成する
  4. jsQR に処理を投げる

といった処理になるだろうか。

早速実装してみよう。

実装

続きを読む

ブラウザのタイトルや URL をコピーするブックマークレット【スマホ&阿部寛対応】

ブラウザで表示しているページのタイトルと URL を一括でコピーしたり、 markdown などのマークアップ言語でフォーマットされたものを、クリップボードにコピーしたくなることは無いだろうか?

意外にも、主要なブラウザには表示ページのタイトル名すら簡単にコピーする方法がない。

いくつかのブラウザ拡張機能(アドオン)には、上述の機能を提供しているものがいくつもある。
しかし、これだけのために拡張機能を入れるのもなんだかなと。
場合によっては、ポリシー等様々な理由で拡張機能を入れることを制限されている場合もあるだろうし。

そこで、表示中ページのタイトルと URL を任意の種類にフォーマットしてクリップボードへコピーしてくれるブックマークレットを作ってみた。

ブックマークレットとした事により、拡張機能の使えないスマートフォンの Chrome や Safari といった、とても不便なブラウザでも利用できる。

使い方

ブラウザのタイトルや URL をコピーするブックマークレット

続きを読む

VSCode + MinGW-w64 via MSYS2 で WIN32API の Unicode ビルド

VSCode + MinGW-w64 via MSYS2 で WIN32API の Unicode ビルド
本記事は C++ Advent Calendar 2023 の6日目の記事だ。

5日目は @uyamae 氏の C++ をclang で解析するときに情報をvcxproj から取得する方法 だった。


Windows 上でサクッと C++ ビルド環境を用意したい

さて、Win32API のコードをビルドしたいけど Visual Studio を入れるまでもない場合、 MinGW の GCC C++ コンパイラ (g++) と Visual Studio Code (VSCode) の組み合わせでも割と快適にビルドできる。

しかし、 VSCode のドキュメントの手順 そのままでは マルチバイト・Unicode周りでハマったので、非ASCII 圏で問題ないように設定する方法を紹介する。

先に解決方法だけ示しておくと、

  1. tasks.json の g++ ビルド時の引数を書き加えてやりつつ

                 "command": "C:\\msys64\\ucrt64\\bin\\g++.exe",
                 "args": [
                     "-fdiagnostics-color=always",
    +                "-DUNICODE",
    +                "-D_UNICODE",
    +                "-municode",
    +                "-std=c++23",
                     "-g",
                     "${file}",
                     "-o",
                     "${fileDirname}\\${fileBasenameNoExtension}.exe"
                 ],
  2. C/C++ extension for VS Code の設定から、 以下の IntelliSense 設定も変えればよい

    • 定義:

      _DEBUG
      UNICODE
      _UNICODE
    • C 標準: c23

    • C++ 標準: C++23

VSCode + MSYS2 上の MinGW-w64 の組み合わせでの設定

続きを読む

Power Automate で少ないステップ数でコレクションを操作するコツ

本記事は、 Microsoft Power Automate Advent Calendar 2023 - シリーズ2 の5日目の記事だ。

"シリーズ1" の4日目は、 @inaho3517 氏の 本でPower Automateを勉強してみた だ。
ちょっとAmazonで検索しただけでも、 めっちゃ本が出てる のね…
知らなかった。
シリーズ2はまだまだ空きがあるので、ぜひご参加を。


実行ステップ数を節約したい

さて、 Power Automate を含め Microsoft Power Platform には、プラン毎に最大要求数の制限がある。
例えば、多くの人が使っているだろう Office 365, Microsoft 365 F3/E3/E5 に含まれる Power Automate の場合、 24時間ごとの 6,000 要求数が上限だ。

Power Automate では、実行されたトリガー・アクションひとつひとつが、結果の成否にかかわらずこの「要求数」を消費する。
大きな数のループや、2重ループなどを行うと、意外と簡単に 6,000 要求数に達してしまう。

時々妥当な範囲で上限を超える程度なら、即時実行をブロックされることはない ものの、設計の段階では超えない事に越したことはない。

唐突だが、アルゴリズムなどの計算量の効率を示す指標として、オーダー表記というものがある。

雑に説明すると、N件のデータを処理するのにどれくらいの勢いで計算コストが増えていくかと言ったもので、例えば単純なループ処理なら O(N), 2重ループとかになると O(N2) といった書き方をするのを、一度は目にしたことがあるのではないだろうか?

ということで、ループによってアクション要求数(ステップ数)が増えがちな Power Automate のコレクションの処理を例に、ループ処理を排除し O(1)定数時間で処理する方法を紹介する。

とりあえず Office Script?

続きを読む

ブラウザ操作中の通信の内容をローカルファイルに自動で保存する

本記事は JavaScript Advent Calendar 2023 の4日目の記事だ。

3日目は @feo52 氏の 最初のレンダリング直前に起動するpagerevealイベント #JavaScript だった。
Window インターフェース に最初のレンダリング直前に呼ばれる pagereveal イベントを追加する提案の実装を Chrome で試してみる内容だ。これは確かに便利そうなイベントに感じる。
令和の IE こと Safari の存在のせいでなかなか Web 標準に組み込まれる敷居が高いものの、是非ワーキンググループでの議論が進んでいただきたいモノだ。
ところで、こういうのって CSS のワーキンググループでドラフトに載ったりするのね。詳しい流れはよく知らんけども。


いにしえの自分の回答がわかりにくい

さて、ブラウザが裏で呼んでいる API の内容をファイルに書き出したかったのだけれども、ファイルサイズが大きいからか開発者ツール経由ではうまく保存できなかった。
そこで、ブラウザ操作中の通信の内容をローカルファイルに自動で保存する方法がなにか無いかな~と探していたら、偶然にも以前に自分自身がスタック・オーバーフローで回答した puppeteer を使った方法についての内容がヒットしてしまった。

すっかり忘れていたのだが、今見返すとちょっとこのままだと使いづらそうなので、もうちょい使いやすくまとめてみる。

基本的には以前に書いた以下の記事と同じ考え方で、 Chrome DevTools ProtocolFetch Domain を直叩きして、特定の通信の内容を横取りしてローカルに保存している。

実際のコード

続きを読む

Docker Compose で、ベースイメージが更新された場合のみ再 up する

本記事は Docker/コンテナ仮想環境 Advent Calendar 2023 の3日目の記事だ。

2日目は @ko-he-8 氏の /var/lib/docker/が肥大化していたけどdocker system prune --volumesで解決しなかったので調べてみた #Docker だった。
なんかの拍子にコンテナが管理外になってしまっていて docker system prune で削除できないときのお話になっている。
開発用の仮想マシンをリセットせずに使い続けていたりすると、こういう状況に良くなるよね…


Docker Compose だけで雑に本番運用する際に、定期的にリビルドしたい

信頼できるオフィシャルイメージを元に、カスタムイメージをビルドして本番運用する場合、 CI 等でビルドしたイメージをコンテナレジストリに push し、それを本番環境側で pull するのが一般的なベストプラクティスだ。

しかし、クラスタも構築せず VM 1台でいくつかのコンテナを動かすような小規模な運用ほ場合、わざわざ CI やレジストリを準備するのも面倒だ。
このため、運用環境上で Docker Compose を使ってイメージのビルドやコンテナの起動を行ってしまう単純な構成にしたくなる。

そんな時、ベースイメージのセキュリティ更新に追従するために、定期的にイメージをリビルドした上で、必要な場合に限ってコンテナを再 create & up させる方法を考える。

BuildX 既定化による弊害

以前は、 docker-compose pull --no-paralleldocker-compose build --pull の標準出力のいずれかから、 新しいイメージが pull されたことを示す "Downloaded newer image" の文字列があるかどうかを確認し、 docker-compose up すればよかった。

ところが、 docker 23.0.0 にて、 Linux 環境における既定のビルダーが BuildKit というものに切り替わってしまった。
旧来の docker-compose V1 の docker-compose build ないし、 Docker Compose V2 の docker compose build 実行時は docker CLI を通じてビルドされる ため、この仕様変更の影響を受ける。
このため、規定の設定のままだと build の仕組みが変わってしまい、上述のベースイメージのダウンロードを検出できなくなった。

BuildKit は規定では出力をいい感じにまとめてしまうので、そのままだとベースイメージの pull があったかどうか判別できない。

環境変数で DOCKER_BUILDKIT=0 を設定しておけば、旧来の Legacy Builder でビルドをしてくれるが、いつまでサポートされるかわからないので、 BuildKit を使う方法でなんとかしたい。

幸い、 docker build --progress=plain の出力の指定 は、 docker compose build でも働いてくれる。

この出力から ^#[0-9]+\s+resolve\s+ の正規表現がヒットする場所を探してくれば検出できそうだ。

Docker Compose V2 に対する出力オプション

また、既に廃止済みの docker-compose V1 の代替として、 Docker Engine 20.10.13Docker Compose V2 プラグイン がインストールされるようになって以降、現在はこちらの docker compose コマンド使う必要がある。

Compose V2 は、多くの面では docker-compose V1 と互換があり、作成されるコンテナ名のセパレータが一致しない事 (これも --compatibility フラグ で互換性を維持できる)以外はおおむねそのまま利用できる。

ただ、コマンドの UI 出力の内容や、それに纏わるオプションは V1 から大きく変わっているので、そこらへんは調整してやる必要がある。

--ansi never オプションを指定すると、ANSI エスケープコードが無効化され、ターミナルの色がつかなくなったり、パイプ時に余計な文字コードが確実につかなくなる…はずなのだが、指定しても up した時のログぐらいにしか効果が出ないような気はする。
規定値だと auto なので、パイプ処理された場合はそもそも ANSI エスケープコードがつかないはずではあるが、とりあえずオプションの方でも never を強制しといた方が良さそうなので設定しておく。

--progress plain オプションを指定すると、インタラクティブな出力が無くなり、以下のようにパイプで処理しやすいプレーンなテキストが出力されるようになる。
Docker Engine 24.0.3 に同梱されている Docker Compose 2.19.0 移行で compose のグローバルオプションに昇格したオプションであるため、それより低いバージョンだと指定できない点に注意。

$ docker compose --progress plain pull
 alpine-built1 Skipped - No image to be pulled
 alpine-built2 Skipped - No image to be pulled
 alpine-pure2 Skipped - Image is already being pulled by alpine-pure1
 alpine-pure1 Pulling
 070eb51debd9 Pulling fs layer
 070eb51debd9 Downloading [>                                                  ]   28.1kB/2.808MB
 070eb51debd9 Downloading [==================================>                ]  1.911MB/2.808MB
 070eb51debd9 Verifying Checksum
 070eb51debd9 Download complete
 070eb51debd9 Extracting [>                                                  ]  32.77kB/2.808MB
 070eb51debd9 Extracting [==================================================>]  2.808MB/2.808MB
 070eb51debd9 Pull complete
 alpine-pure1 Pulled

docker compose build, up のステータスの出力は、標準出力ではなくて標準エラーの方に出るので、パイプラインつなぐときは注意。

実際のコード例

compose.yaml が存在するディレクトリを /var/lib/docker-compose-dir とした場合、以下のようにできるだろう。

cd /var/lib/docker-compose-dir && { \
  /usr/bin/docker compose --ansi never --progress=plain pull --no-parallel; \
  /usr/bin/docker compose --ansi never --progress=plain build --pull; \
} 2>&1 | \
grep -E "Downloaded newer image|\s+Pull complete\s*$|^#[0-9]+\s+resolve\s+" && \
/usr/bin/docker compose --ansi never up -d

--

さて、こういうコードは cron 等で定期的に実行させたい。
そういった場合、あとから状況を確認しやすくするために、 docker compose の各出力は journald にも書き込んでおきたい。

条件分岐を行うための grep と、 journald に記録するコマンド (logger 等) の両方にパイプしたい場合、 bash や BusyBox ash 等が持つ プロセス置換 が使えそうだ。
crontab が起動するコマンドは、 sh という名前で POSIX 標準互換モードで動かすディストリビューションが多い (debian (Ubuntu) 系, fedora (RHEL, CentOS) 系) ので、明示的に bash (または ash) を呼び出し、その中でプロセス置換を行う方が安全だろう。

例えば Ubuntu の crontab 内で定期的にイメージのリビルドを行う場合、以下のようにすると良いだろう。

cd /var/lib/docker-compose-dir && { \
  /usr/bin/docker compose --ansi never --progress=plain pull --no-parallel; \
  /usr/bin/docker compose --ansi never --progress=plain build --pull; \
} 2>&1 | \
bash -c "tee >( logger -i -t user/docker-auto-rebuild -p user.info )" | \
grep -E "Downloaded newer image|\s+Pull complete\s*$|^#[0-9]+\s+resolve\s+" && { \
  /usr/bin/docker compose --ansi never up -d 2>&1 | \
  logger -i -t user/docker-auto-recreate -p user.info; \
}

なお、実際には cron 内のコマンドでは改行できないので、改行は削除して記述しよう。

VSCode で C# のブロック {} 前後の改行の設定を変更する 2023

本記事は C# Advent Calendar 2023 の2日目の記事だ。

1日目は @RyotaMurohoshi 氏の 【Allって】LINQ、この場合どうなる?【空配列は?】 #C# - Qiita だった。

以前バズった空配列議論のツイートを例に、 .NET の LINQ の各エッジケースでどう振る舞うかまとめた記事になっている。
なかなかのボリュームで読み応えがある。

慣れていないと迷ったり勘違いしやすい話なので、参考になる。

C# を K&Rスタイル で整形したい

さて、 C# の既定のコードフォーマットでは、名前空間やクラス、メソッドなど、各種ブロックの {} (中括弧・波括弧) の手前に改行が入る。(所謂、オールマンスタイル)

namespace MyNamespace
{
    class Class1
    {
        static void Main(string[] args)
        {
            if (args.Length > 0)
            {
                ;
            }
            else
            {
                ;
            }
            try
            {
                ;
            }
            catch
            {
                ;
            }
            finally
            {
                ;
            }
        }
    }
}

言語の既定に従うのも悪くは無いとは思う。思うのだが、 Java, JavaScript, Go, Rust 等々、他のメジャーな C言語 スタイルの言語では、 Java のコーディング規約に則って改行を入れないの(K&Rスタイル)が一般的なので、 C# で改行を入れるこのコードスタイルはどうにも気持ちが悪い(主張の強い個人の感想です)

手癖で改行を入れない書き方をしていても、 Shift+Alt+F でドキュメントのフォーマットをすると改行されてしまう。

…と言うことで、 Visual Studio Code (VSCode) を使って C# の開発する際に、各種ブロックの {} (中括弧・波括弧) の手前に改行が入らない形でフォーマットする方法を紹介する。

omnisharp.json は機能しない

vscode でこの設定を変更する場合、古くは omnisharp.json が使われていた。

ところが、 2023年中頃の VSCode の C# 拡張機能の更新 (v2.0.320) で、既定で Roslyn と Razor をベースとした新しい言語サーバーを利用するようになったため、 OmniSharp が使われなくなった。
このため、明示的に OmniSharp を有効 にしない限り、 omnisharp.json に書かれた設定は機能しなくなっている。

.editorconfig を使おう

続きを読む

後ほどミュートを解除しておく PowerShell スクリプト

本記事は シェルスクリプト&PowerShell Advent Calendar 2023 の1日目の記事だ。
如何にハードルを下げるかを考え、しょーもない内容となることを意識している…と言い訳しておこう。

何故ミュートを解除したいのか

さて、一時的に PC をミュートにしておきたい事がある。

コロナ禍を経て、 Cisco や Polycom といったテレビ会議システムに替わって、 Zoom などのWeb会議ソフトが普及した。
しかし、近年出社を強要されるのが一般化してくると、結局以前のように会議室に集まって、離れた拠点の相手とビデオ会議を行うことになる。
このとき、全員各々のPCでビデオ会議には参加するものの、音声は卓上マイク&スピーカー使う事があり、ハウリングを避ける為に卓上マイクを使う人以外はスピーカー・マイクをミュートにするだろう。

ところが、会議終了後ミュートしっぱなしにしてしまい、通知等に気づきにくくなることがあるので、一定時間後にミュートを簡単に解除できるようにしておきたい。

それだけのために、スクリプト経由で MMDevice API 呼ぶのも仰々しいなぁと思っていた所、よく考えたらキーボードにあるミュート状態をトグルキーを仮想的に押せばいいじゃないかと気づいた。

ということで、早速 PowerShell でキーボードのマルチメディアキーを押すスクリプトを書いてみる。

早速コード例

続きを読む

Pester v3 & v5 互換のテストコードを書く (PowerShell)

PowerShell のテストフレームワークである Pester は、単体テストや自動テストなどを手軽に書けるので、スクリプトやコードの品質を保つのに役立つ。

しかし、 Pester は v3 から v5 にかけてかなり大きな破壊的変更がある。

この記事では、 Pester v3 と v5 の両方に互換があるテストコードの書き方について紹介したい。

何故 v3 と v5 で互換を取りたいか

Windows 10 や 11 では、デフォルトで Windows PowerShell 5.1 がインストールされており、更にそこには Pester モジュールの v3.4.0 もインストールされている。
Windows 上の PowerShell モジュールディレクトリはシステム全体で共通のため、たとえ別途 PowerShell 7.3 LTS などをインストールしていたとしても、既定では Pester v3.4.0 が読み込まれるわけだ。

一方、 Linux 等のそれ以外のシステムで PowerShell をインストールした場合は、 Pester が自動的にインストールされることはないため、 Pester モジュールを追加でインストールすることになる。
このとき、普通は最新版の v5 が入るだろう。

Windows PowerShell の Pester を v5 に更新させたり、 Linux 等のシステムでインストールする Pester モジュールを v3.4 に抑えさせたりできればよいが、まぁなかなかそうも行かない時がある。

そんなのっぴきならん状況だと、多少苦労してでもテストコード側を Pester v3 と v5 どちらにも互換を取ってしまったほうが手っ取り早いかも…なんて状況が地球上の何処かには存在するかもしれない。

テストコードの書き方

v3 と v4 の間の破壊的変更で一番デカいのは、 Should 構文の変更で互換切りを行っている部分だ。

続きを読む