JPKI在留申请在线系统证明书模拟提交

模拟点击按钮后直接跳过证书验证并进行下一步操作;支持保存证书内容,可折叠并记住折叠状态

  1. // ==UserScript==
  2. // @name JPKI在留申请在线系统证明书模拟提交
  3. // @name:ja JPKI在留申請オンラインシステムにおける証明書の模擬提出
  4. // @namespace https://www.ras-immi.moj.go.jp/
  5. // @version 1.0.4
  6. // @description 模拟点击按钮后直接跳过证书验证并进行下一步操作;支持保存证书内容,可折叠并记住折叠状态
  7. // @description:ja ボタンをクリックした後、証明書の検証をスキップして次の操作に進む。証明書の内容を保存し、折りたたんで折りたたみ状態を記憶することができます。
  8. // @match *://www.ras-immi.moj.go.jp/WC01/*
  9. // @license MIT
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. "use strict";
  15.  
  16. // 1. 读取 localStorage 中已经保存的证书信息
  17. let mockAuthCert = localStorage.getItem("mockAuthCert") || "";
  18. let mockSignCert = localStorage.getItem("mockSignCert") || "";
  19.  
  20. // 2. 读取面板折叠状态(默认 "true":显示面板;"false":折叠)
  21. // 如果从未设置过,就将其初始化为 "true"
  22. let panelOpen = localStorage.getItem("panelOpen");
  23. if (panelOpen === null) {
  24. panelOpen = "true";
  25. localStorage.setItem("panelOpen", "true");
  26. }
  27.  
  28. // 3. 将“现代化”CSS插入 <head> 中
  29. injectModernStyle();
  30.  
  31. // 4. 创建证书设置面板 和 小圆标按钮
  32. const panel = createSettingPanel();
  33. const openBtn = createOpenButton();
  34.  
  35. // 5. 根据 localStorage 中的 panelOpen 值,设置初始显示/隐藏
  36. if (panelOpen === "true") {
  37. // 显示面板,隐藏小圆标
  38. panel.style.display = "block";
  39. openBtn.style.display = "none";
  40. } else {
  41. // 隐藏面板,显示小圆标
  42. panel.style.display = "none";
  43. openBtn.style.display = "block";
  44. }
  45.  
  46. // 6. 绑定页面按钮(登录(不可用)/届出等)事件
  47. bindButtonEvents();
  48.  
  49. /**
  50. * 面板样式
  51. */
  52. function injectModernStyle() {
  53. const styleEl = document.createElement("style");
  54. styleEl.innerHTML = `
  55. /* 悬浮面板总体样式 */
  56. #custom-cert-panel {
  57. position: fixed;
  58. right: 20px;
  59. bottom: 20px;
  60. width: 320px;
  61. padding: 15px 15px 10px;
  62. background-color: #fff;
  63. border: 1px solid #dadada;
  64. border-radius: 8px;
  65. box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  66. font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  67. font-size: 14px;
  68. z-index: 99999;
  69. color: #333;
  70. }
  71. /* 面板标题 */
  72. #custom-cert-panel h2 {
  73. margin: 0 0 10px 0;
  74. font-size: 16px;
  75. font-weight: 600;
  76. padding-right: 24px; /* 给右上角的关闭按钮留空间 */
  77. }
  78. /* 通用标签样式 */
  79. .modern-label {
  80. display: block;
  81. margin-top: 10px;
  82. font-weight: 600;
  83. }
  84. /* 文本域样式 */
  85. .modern-textarea {
  86. width: 100%;
  87. height: 50px;
  88. resize: vertical;
  89. padding: 6px 8px;
  90. margin-top: 4px;
  91. border: 1px solid #ccc;
  92. border-radius: 4px;
  93. font-family: inherit;
  94. font-size: 14px;
  95. box-sizing: border-box;
  96. }
  97. /* 按钮容器 */
  98. .button-container {
  99. margin-top: 12px;
  100. text-align: right;
  101. }
  102. /* 通用按钮样式 */
  103. .modern-button {
  104. padding: 6px 12px;
  105. border: none;
  106. border-radius: 4px;
  107. background-color: #387ef5;
  108. color: #fff;
  109. cursor: pointer;
  110. font-size: 14px;
  111. margin-right: 10px;
  112. }
  113. .modern-button:hover {
  114. background-color: #226ad4;
  115. }
  116. .modern-button:active {
  117. background-color: #1c56a5;
  118. }
  119. /* 关闭按钮 (右上角的 × ) */
  120. .close-btn {
  121. position: absolute;
  122. top: 10px;
  123. right: 10px;
  124. cursor: pointer;
  125. font-size: 18px;
  126. color: #999;
  127. }
  128. .close-btn:hover {
  129. color: #666;
  130. }
  131.  
  132. /* 小圆标按钮样式(折叠后的“+”按钮) */
  133. #open-panel-button {
  134. position: fixed;
  135. right: 20px;
  136. bottom: 20px;
  137. width: 45px;
  138. height: 45px;
  139. background-color: #387ef5;
  140. color: #fff;
  141. border-radius: 22px;
  142. cursor: pointer;
  143. text-align: center;
  144. line-height: 40px;
  145. font-weight: bold;
  146. font-size: 26px;
  147. box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  148. user-select: none;
  149. z-index: 99998;
  150. }
  151. #open-panel-button:hover {
  152. background-color: #226ad4;
  153. }
  154. #open-panel-button:active {
  155. background-color: #1c56a5;
  156. }
  157. `;
  158. document.head.appendChild(styleEl);
  159. }
  160.  
  161. /**
  162. * 面板
  163. */
  164. function createSettingPanel() {
  165. // 容器
  166. const panel = document.createElement("div");
  167. panel.id = "custom-cert-panel";
  168.  
  169. // 关闭按钮
  170. const closeBtn = document.createElement("div");
  171. closeBtn.className = "close-btn";
  172. closeBtn.innerHTML = "&times;";
  173. closeBtn.addEventListener("click", () => {
  174. // 隐藏面板
  175. panel.style.display = "none";
  176. // 显示小圆标
  177. openBtn.style.display = "block";
  178. // 记住折叠状态
  179. localStorage.setItem("panelOpen", "false");
  180. });
  181. panel.appendChild(closeBtn);
  182.  
  183. // 标题
  184. const title = document.createElement("h2");
  185. title.innerText = "模拟证书设置";
  186. panel.appendChild(title);
  187.  
  188. // 利用者証明書
  189. const labelAuth = document.createElement("label");
  190. labelAuth.className = "modern-label";
  191. labelAuth.innerText = "利用者証明書:";
  192. panel.appendChild(labelAuth);
  193.  
  194. const inputAuth = document.createElement("textarea");
  195. inputAuth.className = "modern-textarea";
  196. inputAuth.value = mockAuthCert;
  197. panel.appendChild(inputAuth);
  198.  
  199. // 署名証明書
  200. const labelSign = document.createElement("label");
  201. labelSign.className = "modern-label";
  202. labelSign.innerText = "署名証明書:";
  203. panel.appendChild(labelSign);
  204.  
  205. const inputSign = document.createElement("textarea");
  206. inputSign.className = "modern-textarea";
  207. inputSign.value = mockSignCert;
  208. panel.appendChild(inputSign);
  209.  
  210. // 按钮容器
  211. const buttonContainer = document.createElement("div");
  212. buttonContainer.className = "button-container";
  213.  
  214. // 保存按钮
  215. const saveButton = document.createElement("button");
  216. saveButton.className = "modern-button";
  217. saveButton.innerText = "保存";
  218. saveButton.addEventListener("click", function () {
  219. let authVal = inputAuth.value.trim();
  220. let signVal = inputSign.value.trim();
  221.  
  222. // 如果包含 BEGIN/END,则自动去除头尾
  223. const regCert = /-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/i;
  224.  
  225. // 去除認証証明書头尾并去除换行
  226. if (regCert.test(authVal)) {
  227. authVal = authVal.replace(regCert, "$1").trim();
  228. authVal = authVal.replace(/\r?\n/g, "");
  229. }
  230. // 去除署名証明書头尾并去除换行
  231. if (regCert.test(signVal)) {
  232. signVal = signVal.replace(regCert, "$1").trim();
  233. signVal = signVal.replace(/\r?\n/g, "");
  234. }
  235.  
  236. // 去除空行空格
  237. authVal = authVal.replace(/\s+/g, "");
  238. authVal = authVal.replace(/^\s*[\r\n]/gm, "");
  239. signVal = signVal.replace(/\s+/g, "");
  240. signVal = signVal.replace(/^\s*[\r\n]/gm, "");
  241.  
  242. // 存入 localStorage
  243. localStorage.setItem("mockAuthCert", authVal);
  244. localStorage.setItem("mockSignCert", signVal);
  245.  
  246. // 同步脚本内的变量
  247. mockAuthCert = authVal;
  248. mockSignCert = signVal;
  249.  
  250. alert("证书内容已保存!(已自动去除 CERT 头尾和多余换行)");
  251. });
  252. buttonContainer.appendChild(saveButton);
  253.  
  254. // 清空按钮
  255. const clearButton = document.createElement("button");
  256. clearButton.className = "modern-button";
  257. clearButton.innerText = "清空";
  258. clearButton.addEventListener("click", function () {
  259. localStorage.removeItem("mockAuthCert");
  260. localStorage.removeItem("mockSignCert");
  261. mockAuthCert = "";
  262. mockSignCert = "";
  263. inputAuth.value = "";
  264. inputSign.value = "";
  265. alert("证书内容已清空!");
  266. });
  267. buttonContainer.appendChild(clearButton);
  268.  
  269. panel.appendChild(buttonContainer);
  270.  
  271. // 把面板插入页面
  272. document.body.appendChild(panel);
  273.  
  274. return panel;
  275. }
  276.  
  277. /**
  278. * 创建折叠后的“小圆标”按钮,用于重新展开面板
  279. */
  280. function createOpenButton() {
  281. const openBtn = document.createElement("div");
  282. openBtn.id = "open-panel-button";
  283. openBtn.innerHTML = "+";
  284. // 先不设置 display: none,这里会通过脚本动态决定
  285. openBtn.style.display = "none";
  286.  
  287. openBtn.addEventListener("click", () => {
  288. // 显示面板
  289. panel.style.display = "block";
  290. // 隐藏小圆标
  291. openBtn.style.display = "none";
  292. // 记住展开状态
  293. localStorage.setItem("panelOpen", "true");
  294. });
  295.  
  296. document.body.appendChild(openBtn);
  297. return openBtn;
  298. }
  299.  
  300. /**
  301. * 绑定页面按钮(登录(不可用)/届出)事件:当用户点击时,拦截并自动填充表单
  302. */
  303. function bindButtonEvents() {
  304. // 监听 clickLogInKjnBtn
  305. waitForElement("[name=clickLogInKjnBtn]", function (button) {
  306. console.log("找到按钮 clickLogInKjnBtn");
  307. button.addEventListener("click", function (event) {
  308. event.preventDefault();
  309. simulateCertSuccess("clickLogInKjnBtn");
  310. });
  311. });
  312.  
  313. // 监听 clickTurkKjnBtn
  314. waitForElement("[name=clickTurkKjnBtn]", function (button) {
  315. console.log("找到按钮 clickTurkKjnBtn");
  316. button.addEventListener("click", function (event) {
  317. event.preventDefault();
  318. simulateCertSuccess("clickTurkKjnBtn");
  319. });
  320. });
  321. }
  322.  
  323. /**
  324. * 自动填充并提交表单的核心逻辑
  325. */
  326. function simulateCertSuccess(btnname) {
  327. console.log("模拟证书处理...");
  328.  
  329. // 没有填写必要证书时,阻止操作
  330. if (!mockAuthCert) {
  331. alert("模拟证书:未填写認証用証明書");
  332. return;
  333. }
  334. if (btnname === "clickTurkKjnBtn" && !mockSignCert) {
  335. alert("模拟证书:未填写署名用証明書");
  336. return;
  337. }
  338.  
  339. // 将证书写入隐藏字段(根据实际页面的字段名称来修改)
  340. document.getElementById("hdnUsrCert").value = mockAuthCert;
  341. if (btnname === "clickTurkKjnBtn") {
  342. document.getElementById("hdnSignCert").value = mockSignCert;
  343. }
  344.  
  345. // 创建隐藏按钮用于提交
  346. const form = document.getElementById("WCAAS010Dto"); // 根据实际表单 ID 修改
  347. let input = document.getElementById(btnname);
  348. if (!input) {
  349. input = document.createElement("input");
  350. input.type = "hidden";
  351. input.id = btnname;
  352. input.name = btnname;
  353. form.appendChild(input);
  354. }
  355.  
  356. // 提交表单
  357. form.submit();
  358. console.log("表单已提交!按钮:" + btnname);
  359. }
  360.  
  361. /**
  362. * 等待某个选择器元素出现
  363. */
  364. function waitForElement(selector, callback) {
  365. const element = document.querySelector(selector);
  366. if (element) {
  367. callback(element);
  368. } else {
  369. setTimeout(() => waitForElement(selector, callback), 500);
  370. }
  371. }
  372. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址