信州大学ACSU多要素認証の自動化
2025年8月09日概要
多要素認証がめんどくさかったので、信州大学ACSUの多要素認証「WisePoint」のイメージ認証を自動化するTampermonkeyユーザースクリプト「wisepoint-auto」を作成しました。
GitHubリポジトリ:UltiMorse/wisepoint-auto
出席登録のQRコードで毎回認証があるのがめんどくさいですが、Tampermonkeyをインストールすれば同様にiPhoneのsafariでも動きました。スマホで拡張機能が使えるブラウザはSafariかFirefoxくらいですかね。
こっちの記事でiOSアプリのTampermonkeyとUserScriptsを比較しているので、iPhoneでユーザースクリプトを使いたい人はそちらもどうぞ。
おことわり:
本スクリプトは検証目的であり、実運用や利用は各自の判断でお願いします。
WisePointイメージ認証の仕様(認証画面やDevToolsで見た感じ)
- 5×5のマスが画面上に表示される
- 各マスは
(N=0〜24)で表現<div class="input_imgdiv_class" id="buttonN" ...> - 画像は
で指定style="background-image:url('/idp/tenant/0/images/imatrix/iXX.gif')" - 配置は毎回ランダム。GIF画像のファイル名からアルファベットを判定
自動化の流れ
- マスの各divから background-image のファイル名を取得
- ファイル名からアルファベットを判定
- ユーザーが設定した順番(例:A→B→C→D)で該当するマスをクリック
- input#btnLoginをクリック
使い方
- Chrome拡張Tampermonkeyをインストール
- Chrome拡張の開発者モード(デベロッパーモード)をオンにし、詳細のところやブラウザの設定からユーザースクリプトの実行を許可
この画像はBraveブラウザの例です。(Chromium系なのでChromeとほとんど同じはず。)拡張機能一覧で詳細を開くか、タスクバーのアイコンから開くかしてください。
- GitHubリポジトリからスクリプトを取得あるいは以下のスクリプトをコピペ
- Tampermonkeyで新規スクリプトとして追加
- スクリプト内の
const PASSWORD = ["A","B","C","D"];を自分の設定したパスワードに編集 - 設定後に再読み込みして、WisePointイメージ認証画面で自動クリックが動作することを確認
- 動作しなければユーザースクリプトの実行の許可などの設定を見直してください。
スクリプト本体
// ==UserScript==
// @name wisepoint-auto
// @namespace https://github.com/UltiMorse/wisepoint-auto
// @version 2025-08-11
// @description ACSUのマトリクス認証自動入力ボタン追加
// @author UltiMorse
// @match https://gakunin.ealps.shinshu-u.ac.jp/idp/Authn/External?conversation=*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 設定:自動クリックするパスワード(順番にクリックされるアルファベット)
const PASSWORD = ['', '', '', '']; // ['A', 'B', 'C', 'D']; のようにパスワードを設定
// --- UI ---
// 自動入力ボタンをログインボタンの左隣に追加
function addAutoButton() {
if (document.getElementById('autoInputBtn')) return;
const btn = document.createElement('button');
btn.id = 'autoInputBtn';
btn.textContent = '自動入力';
btn.type = 'button';
btn.className = 'form-matrix-button form-button';
btn.onclick = autoInput;
const loginBtn = document.getElementById('btnLogin');
if (loginBtn) {
btn.style.height = loginBtn.offsetHeight + 'px';
btn.style.fontSize = window.getComputedStyle(loginBtn).fontSize;
btn.style.padding = window.getComputedStyle(loginBtn).padding;
btn.style.marginRight = '8px';
}
if (loginBtn && loginBtn.parentNode) {
loginBtn.parentNode.insertBefore(btn, loginBtn);
} else {
document.body.appendChild(btn);
}
}
// --- クリック ---
// i1.gif→A, i2.gif→B,...i16.gif→P, i17.gif→R,...i25.gif→Z(Qなし)で判定しクリック
function clickMatrixChar(char) {
const letters = [];
for (let i = 0, code = 65; i < 25; i++, code++) {
if (String.fromCharCode(code) === 'Q') code++;
letters.push(String.fromCharCode(code));
}
const btns = document.querySelectorAll('.input_imgdiv_class');
for (let btn of btns) {
const bg = btn.style.backgroundImage;
const m = bg.match(/i(\d{1,2})\.gif/i);
if (m) {
const idx = parseInt(m[1], 10) - 1;
if (letters[idx] === char) {
btn.click();
return true;
}
}
}
return false;
}
// --- 自動入力 ---
async function autoInput() {
for (const c of PASSWORD) {
const ok = clickMatrixChar(c);
if (!ok) {
alert('エラー');
return;
}
await new Promise(r => setTimeout(r, 200));
}
const loginBtn = document.getElementById('btnLogin');
if (loginBtn) {
setTimeout(() => loginBtn.click(), 200);
}
}
// --- マトリクス出現監視 ---
function waitAndAddButton() {
if (document.getElementById('autoInputBtn')) return;
const matrix = document.querySelector('[id^="button0"].input_imgdiv_class');
if (matrix) {
addAutoButton();
return;
}
const observer = new MutationObserver(() => {
const m = document.querySelector('[id^="button0"].input_imgdiv_class');
if (m) {
addAutoButton();
observer.disconnect();
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
// --- 初期化 ---
if (document.readyState === 'loading') {
window.addEventListener('DOMContentLoaded', waitAndAddButton);
} else {
waitAndAddButton();
}
})();
補足・注意事項
- WisePointの仕様変更等で動作しなくなる場合があります
- お気づきの点やご意見はXやメールでお気軽にどうぞ
まとめ
ブックマークレットとかでやっている人は工学部の同期でかなり多いですが、ボタン一発でできたり、iPhoneなどスマホで使えたりというのは結構便利かと思います。
関連記事: