Laravelが画面を配信し、ブラウザー内でパスワードを生成・表示・コピーする構成

Laravelのアプリでも、すべての処理をPHPで行う必要はありません。
パスワード生成なら、Laravelで画面を配信し、JavaScriptで生成することで、生成値をサーバーへ送らずに使えるツールを作れます。
この記事では、PHPの基本を知っているLaravel初学者に向けて、画面と生成処理の分け方を説明します。

条件入力と結果を1画面にまとめる

文字数・発行数の設定と、5件の結果をテキストエリアに表示した画面

完成例は8〜128文字、1回1〜100件を生成できます。
英小文字・英大文字・数字・記号を選び、記号はプリセットか直接入力で指定します。
結果は改行区切りのテキストエリアに全件表示し、まとめてコピーできます。

パスワード生成を試す

編集先 担当する処理
routes/web.php 画面を返すGETのURLを用意する
resources/views/tools/password-browser.blade.php 条件入力・結果・操作ボタンを置く
resources/js/browser-password-engine.js 入力の検証とパスワード生成
resources/js/browser-password.js ボタン操作・表示・コピー

先に生成関数を作り、Bladeで入力と結果の置き場所を用意して、画面操作のJavaScriptから関数を呼びます。
生成用のPOST先や保存用のModelは使いません。

使う文字を決め、暗号用途の乱数で選ぶ

文字種ごとに使える文字を定義し、選択されたものをつなげて抽選対象にします。
記号を直接入力させる場合は半角記号だけを受け付け、重複を取り除きます。
たとえば!@#なら、その3種類を記号として使います。利用先で認められる記号を選べるようにするためです。

乱数にはブラウザー標準のcrypto.getRandomValuesを使います。
得られた値を文字数で割った余りに変換する際は、割り切れない末尾を捨てて引き直すと抽選の偏りを避けられます。
次は、文字の位置を1つ選ぶ処理を抜き出した例です。

function randomIndex(size) {
    const buffer = new Uint32Array(1);
    const limit = Math.floor(2 ** 32 / size) * size;
    do {
        crypto.getRandomValues(buffer);
    } while (buffer[0] >= limit);
    return buffer[0] % size;
}

sizeには、入力検証済みの文字集合の長さを渡します。
選んだ文字種をすべて含めるには、候補を作った後に条件を調べ、足りない文字種があれば候補全体を作り直します。
乱数機能が使えない場合は生成を止め、再抽選にも試行回数の上限を設けます。

生成結果をテキストエリアへ表示する

生成関数は、文字数・発行数・文字種を受け取り、文字列の配列を返す形にします。
画面側ではボタンを押したときに呼び出し、配列を改行でつないで表示します。

const passwords = generatePasswords({
    length: 16,
    count: 5,
    groups: ['lowercase', 'uppercase', 'numbers'],
});

allResults.value = passwords.join('\n');
allResults.hidden = false;
allResults.style.height = 'auto';
allResults.style.height = `${allResults.scrollHeight + 2}px`;

ここでは条件を固定していますが、画面では入力欄の値を渡します。
テキストエリアは読み取り専用にし、長い行を折り返します。内容に合わせて高さを調整すれば、長いパスワードも全文を見られます。
表示にはinnerHTMLを使わずvalueへ設定すると、<などの記号もHTMLとして解釈されません。

コピーと消去を画面内で完結させる

「全件コピー」ボタンから、Clipboard.writeTextへテキストエリアの値を渡します。

await navigator.clipboard.writeText(allResults.value);

コピーが許可されない場合もあるため、失敗時はテキストを選択して手動コピーを案内します。
条件を変更したときや画面を離れるときは、古い結果が残らないよう表示を消します。
コピー済みの値はクリップボードに残る場合があり、画面の消去とは別です。

生成値はフォーム送信、ログ、DB、Web Storageへ渡さず、画面内だけで扱います。
通信を制限するCSPやno-storeも応答に付けますが、表示した値のメモリーからの完全消去を保証するものではありません。

まとめ

Laravelで画面を配信し、JavaScriptで生成すれば、パスワードをサーバーへ送らずに使えるツールを作れます。
暗号用途の乱数と入力条件を押さえ、生成処理・結果表示・コピーを分けて実装すると、文字種や画面の変更にも対応しやすくなります。