// ==UserScript== // @name OTP NTFY Console (Token) // @namespace http://tampermonkey.net/ // @version 2.2 // @description Pannello OTP sicuro con Bearer Token e monitoraggio live // @author Gemini + Gatto // @match *://www.ilportaledellautomobilista.it/* // @grant GM_notification // @grant GM_setClipboard // ==/UserScript== (function() { 'use strict'; // --- CONFIGURAZIONE SICURA --- const BASE_URL = "ntfy.dati-web.it"; // <--- INCOLLA QUI IL TUO TOKEN tk_... const NTFY_TOKEN = "tk_mh1ox5scgkorten10a7baelpehh6p"; let currentTopic = localStorage.getItem('otp_topic'); let mode = localStorage.getItem('otp_mode'); const OTP_REGEX = /(?:^|\s)(\S{8})(?=\s|$)/; function injectInterface() { const logo = document.getElementById('logo-portale'); if (!logo) { setTimeout(injectInterface, 500); return; } const parentLink = logo.closest('a'); const anchorPoint = parentLink ? parentLink : logo; if (document.getElementById('otp-embedded-panel')) return; const navPanel = document.createElement('div'); navPanel.id = "otp-embedded-panel"; // Stile del pannello navPanel.style = ` display: inline-flex; align-items: center; gap: 4px; margin-left: 330px; margin-top: 16px; padding: 0 10px; background: #ffffff; border: 1px dashed #0056b3; border-radius: 6px; vertical-align: middle; height: 60px; font-family: Arial, sans-serif; box-sizing: border-box; cursor: default; pointer-events:auto; position: relative; z-index: 10; min-width: 340px !important; max-width: 420px !important; box-shadow: 0 2px 5px rgba(0,0,0,0.1) !important; line-height: normal; color: #333 !important; ` ; navPanel.innerHTML = `
---
STABILE
`; anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling); // Salvataggio impostazioni document.getElementById('saveConfig').addEventListener('click', () => { localStorage.setItem('otp_topic', document.getElementById('topicInput').value.trim()); localStorage.setItem('otp_mode', document.querySelector('input[name="otpMode"]:checked').value); location.reload(); }); startListening(); } async function startListening() { const statusLabel = document.getElementById('statusLabel'); try { const response = await fetch(`https://${BASE_URL}/${currentTopic}/json`, { headers: { "Authorization": `Bearer ${NTFY_TOKEN}` } }); if (response.status === 401 || response.status === 403) { statusLabel.innerText = "ERRORE TOKEN"; statusLabel.style.color = "red"; return; } if (!response.ok) throw new Error("Errore connessione"); statusLabel.innerText = "ONLINE"; statusLabel.style.color = "#28a745"; const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { value, done } = await reader.read(); if (done) break; const chunk = decoder.decode(value); const lines = chunk.split('\n'); for (const line of lines) { if (!line.trim()) continue; try { const data = JSON.parse(line); if (data.event === 'message' && data.message) { const match = data.message.match(OTP_REGEX); if (match) handleOTP(match[1]); } } catch (e) { console.error("Errore parsing JSON", e); } } } } catch (err) { statusLabel.innerText = "RE-CONNECTING..."; statusLabel.style.color = "orange"; setTimeout(startListening, 5000); } } function handleOTP(newOtp) { document.getElementById('lastCodeLabel').innerText = newOtp; GM_setClipboard(newOtp); // Notifica di sistema GM_notification({ title: "OTP Infocert", text: `Codice: ${newOtp} (Copiato)`, timeout: 5000 }); // Se la modalità è "Digita", inserisce l'OTP nel campo attualmente selezionato (focus) if (document.querySelector('input[name="otpMode"]:checked').value === 'type') { const activeInput = document.activeElement; // Verifichiamo che l'elemento attivo sia effettivamente un campo di testo if (activeInput && (activeInput.tagName === 'INPUT' || activeInput.tagName === 'TEXTAREA')) { activeInput.value = newOtp; // Simula l'evento di input per attivare eventuali validazioni/script della pagina activeInput.dispatchEvent(new Event('input', { bubbles: true })); activeInput.dispatchEvent(new Event('change', { bubbles: true })); } else { console.warn("Nessun campo di testo selezionato al momento dell'inserimento."); } } } if (document.readyState === "complete" || document.readyState === "interactive") { injectInterface(); } else { document.addEventListener("DOMContentLoaded", injectInterface); } })();