Movatterモバイル変換


[0]ホーム

URL:


はてラボはてな匿名ダイアリー
ようこそ ゲスト さんログインユーザー登録
< anond:20250613184753 |anond:20250613033142 >

2025-06-13

我が名はサイボーグdorawii

パーマリンク署名対象にするより堅牢自動化を作れた。

一度投稿したうえで別タブを開いてプログラム的(fetch)に送信してその別タブが閉じられる仕組み。

改めてスクリプト配布しちゃる

最初投稿してエントリページに移動した親タブ側のjsコード
// ==UserScript==      // @namePGP署名検出と別タブ自動編集      // @namespacehttp://tampermonkey.net/      // @version      1.0      // @descriptionPGP署名がない投稿自動編集ページへ誘導      // @matchhttps://anond.hatelabo.jp/*      // @grantGM_setValue      // @grantGM_getValue      // @grantGM.openInTab      // ==/UserScript==      (function () {        'use strict';constbody = document.getElementById('entry-page');        if (!body) return;consttitleText = document.title;        if (!titleText.includes('dorawii')) return;constpgpRegex = /BEGIN.*PGP(?: SIGNEDMESSAGE| SIGNATURE)?/;const preElements = document.querySelectorAll('div.body pre');        let hasPgpSignature =false;        for (const pre of preElements) {          if (pgpRegex.test(pre.textContent)) {            hasPgpSignature =true;            break;          }        }        if (hasPgpSignature) return;const editLink = document.querySelector('a.edit');const childTab =GM.openInTab(editLink.href, {active:false, insert:true,setParent:true });      })();
親タブから開かれる編集ページの子タブのjsコード
 // ==UserScript==      // @name編集ページ処理と自動送信・閉じ      // @namespacehttp://tampermonkey.net/      // @version      1.0      // @description編集ページで署名処理と送信、タブ自動閉じ      // @matchhttps://anond.hatelabo.jp/dorawii_31/edit?id=*      // @grantGM_getValue      // @grantGM_xmlhttpRequest      // @grantGM_setClipboard      // @grantGM_notification      // @connectlocalhost      // ==/UserScript==      (async function () {        'use strict';const shouldRun = awaitGM_getValue('open-tab-for-edit', '0');consttextareaId = 'text-body';consttextarea = document.getElementById(textareaId);        if (!textarea) return;const content =textarea.value;constpgpSignatureRegex = /-----BEGINPGP SIGNEDMESSAGE-----[\s\S]+?-----BEGINPGP SIGNATURE-----[\s\S]+?-----ENDPGP SIGNATURE-----/;        if (pgpSignatureRegex.test(content)) {console.log('[PGPスクリプト]署名が検出されたためそのまま送信します');          return;        }consthttpRequest = (url, data) =&gt; {          return newPromise((resolve,reject) =&gt; {GM_xmlhttpRequest({              method: 'POST',url:url,              headers: { 'Content-Type': 'application/x-www-form-urlencoded' },              data: `value=${encodeURIComponent(data)}`,onload: function (response) {                resolve(response.responseText);              },onerror: function (error) {reject(error);              }            });          });        };        //textarea の値を取得        // 1.現在のページのURLからURLオブジェクト作成const currentUrl = newURL(window.location.href);        // 2.ベースとなる部分 (例: "https://anond.hatelabo.jp") を取得constorigin = currentUrl.origin;        // 3. 'id'パラメータの値 (例: "20250610184705") を取得constidValue = currentUrl.searchParams.get('id');        // 4.ベース部分とIDを結合して、目的URL文字列を生成        //idValueが取得できた場合のみ実行する        let newUrl = null;        if (idValue) {          newUrl = `${origin}/${idValue}`;        }        // 5. 生成されたURL変数に代入し、コンソールに出力して確認console.log(newUrl);constvalueToSend = newUrl;try {const signatureText = awaithttpRequest('http://localhost:12345/run-batch',valueToSend);console.log('バッチ応答:', signatureText);          if (!signatureText.includes('BEGINPGP SIGNEDMESSAGE')) {            alert('PGP署名クリップボードに見つかりませんでした。');            return;          }const newText = content.replace(/\s*$/, '') + '\n' + signatureText + '\n';textarea.value = newText;console.log('[PGPスクリプト]署名を貼り付けました。送信を再開します。');const form = document.forms.edit;const newForm = form.cloneNode(true);          form.replaceWith(newForm);          newForm.addEventListener('submit', async (e) =&gt; {            e.preventDefault(); //HTML標準のsubmitをキャンセルconstbodyText =textarea?.value || '';            //reCAPTCHAトークンの取得constrecaptchaToken = await newPromise((resolve) =&gt; {              grecaptcha.enterprise.ready(() =&gt; {                grecaptcha.enterprise.execute('hoge', {action: 'EDIT' })                  .then(resolve);              });            });            // POSTするデータの構築const formData = new FormData(newForm);            formData.set('body',bodyText);            formData.set('recaptcha_token',recaptchaToken);            formData.set('edit', '1');try {constresponse = await fetch(newForm.action, {                method: 'POST',body: formData,                credentials: 'same-origin'              });              if (response.ok) {console.log('送信成功');                window.close();              } else {console.error('送信失敗',response.status);              }            }catch (err) {console.error('送信中にエラーが発生', err);            }          });          //プログラム的に送信トリガー          newForm.dispatchEvent(new Event('submit', { bubbles:true }));        }catch (e) {console.error('バッチ呼び出し失敗:', e);        }      })();
node.jsで動かすローカルサーバーコード
consthttp =require('http');const { exec } =require('child_process');const querystring =require('querystring');const server =http.createServer((req, res) =&gt; {  if (req.method === 'GET' &amp;&amp; req.url === '/ping') {    res.writeHead(200);    res.end('pong');  } else if (req.method === 'POST' &amp;&amp; req.url === '/run-batch') {    letbody = '';    req.on('data', chunk =&gt; {body += chunk.toString();    });    req.on('end', () =&gt; {constparsed = querystring.parse(body);constvalue =parsed.value || 'default';      // 値を引数としてバッチに渡す      exec(`C:\\Users\\hoge\\Desktop\\makesign.bat "${value}"`, { encoding: 'utf8' }, (err, stdout, stderr) =&gt; {        if (err) {          res.writeHead(500);          res.end('Error executing batch: ' + stderr);        } else {          res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });          res.end(stdout.trim());        }      });    });  } else {    res.writeHead(404);    res.end('Not found');  }});server.listen(12345, () =&gt; {console.log('Batch serverrunningathttp://localhost:12345/');});
@echo offsetlocal enabledelayedexpansion::署名するファイルset "infile=%~1"set outfile=%TEMP%\pgp_output.asc:: 以前の出力があれば削除if exist "%outfile%" del "%outfile%":signloop::AutoHotkeyパスフレーズ入力(gpgがパスワード要求するダイアログが出た場合に備える)start "" /b "C:\Users\hoge\Documents\AutoHotkey\autopass.ahk"::PGPクリア署名作成echo %infile% | gpg --yes --clearsign --output "%outfile%"::署名成功していればループを抜けるif exist "%outfile%" (goto postprocess) else (    timeout /t 1&gt; nulgoto signloop):postprocesspowershell -nologo -command ^  "$header = '&gt;|'; $footer = '|&lt;'; $body =Get-Content '%outfile%' -Raw;Write-Output ($header + \"`r`n\" + $body + $footer)"powershell -nologo -command ^  "$header = '&gt;|'; $footer = '|&lt;'; $body =Get-Content 'signed.asc' -Raw;Set-Clipboard -Value ($header + \"`r`n\" + $body + $footer)"endlocalexit /b
AutoHotkey(以前と同じ)
#Persistent#SingleInstance ignoreSetTitleMatchMode, 2WinWaitActive, pinentrySendInputpasswordSleep 100SendInput {Enter}ExitApp

動けばいいという考えで作っているので余分なコードも含んでいるかもしれない。

-----BEGINPGP SIGNEDMESSAGE-----Hash: SHA512https://anond.hatelabo.jp/20250613185036 -----BEGINPGP SIGNATURE-----iHUEARYKAB0WIQTEe8eLwpVRSViDKR5wMdsubs4+SAUCaEv1FQAKCRBwMdsubs4+SHHkAQDUOLgBcdji2T6MJ7h/vlMdFfGlWAzNdXijjE1gIuEPywEAiMNMZqhrMmtlc7UqRuggNJ/UTa5xTIcKp622+7jJQQg==Lgkl-----ENDPGP SIGNATURE-----

Permalink |記事への反応(1) | 18:50

このエントリーをはてなブックマークに追加ツイートシェア

記事への反応 -

記事への反応(ブックマークコメント)

全てのコメントを見る

人気エントリ

注目エントリ

ログインユーザー登録
ようこそ ゲスト さん
Copyright (C) 2001-2026 hatena. All Rights Reserved.

[8]ページ先頭

©2009-2026 Movatter.jp