Files
script/OTP Portale Automobilista, Multi-Tab OK require.user.js-2d2741c2671aeb7b4ea66d0374401b49-OTP_Multi-Tab.js
2026-05-12 21:05:35 +02:00

158 lines
6.7 KiB
JavaScript

(function() {
'use strict';
const API_URL = "https://umctv.altervista.org/hook/OTP.php";
const POLLING_RATE = 8000;
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";
navPanel.style = `
display: inline-flex;
align-items: center;
gap: 6px;
margin-left: 300px;
margin-top: 25px;
padding: 0 10px;
background: #ffffff;
border: 1px dashed #0056b3;
border-radius: 4px;
vertical-align: middle;
height: 56px;
font-family: Arial, sans-serif;
box-sizing: border-box;
cursor: default;
pointer-events: auto;
position: relative;
z-index: 10;
`;
navPanel.innerHTML = `
<div style="font-size: 10px; font-weight: bold; color: #0056b3; line-height: 1; text-align: center;">OTP<br>LOG</div>
<input type="password" id="authCode" placeholder="Secret" style="width: 85px; height: 20px; padding: 2px; border: 1px solid #ccc; border-radius: 2px; font-size: 10px; margin: 0; cursor: text;">
<div style="display: flex; flex-direction: column; gap: 1px;">
<button id="saveBtn" title="Salva Secret" style="padding: 1px 4px; background: #007bff; color: white; border: none; border-radius: 2px; cursor: pointer; font-size: 8px; height: 11px; line-height: 1;">S</button>
<button id="resetBtn" title="Reset Dati" style="padding: 1px 4px; background: #6c757d; color: white; border: none; border-radius: 2px; cursor: pointer; font-size: 8px; height: 11px; line-height: 1;">R</button>
</div>
<div style="border-left: 1px solid #ddd; height: 20px; margin: 0 4px;"></div>
<div style="text-align: center; min-width: 70px;">
<div id="lastCodeLabel" style="font-size: 13px; font-weight: bold; color: #d9534f; line-height: 1;">---</div>
<div id="statusLabel" style="font-size: 7px; color: #28a745; font-weight: bold; text-transform: uppercase;">In ascolto</div>
</div>
`;
anchorPoint.parentNode.insertBefore(navPanel, anchorPoint.nextSibling);
startMonitoring();
}
function startMonitoring() {
const authInput = document.getElementById('authCode');
const statusLabel = document.getElementById('statusLabel');
const lastCodeLabel = document.getElementById('lastCodeLabel');
authInput.value = localStorage.getItem('otp_secret_vault') || "";
// Carichiamo l'ultimo OTP dal localStorage (condiviso tra tab)
let lastOtp = localStorage.getItem('last_detected_otp') || "";
if (lastOtp) {
lastCodeLabel.innerText = lastOtp;
}
function checkOTP() {
const secret = localStorage.getItem('otp_secret_vault');
if (!secret || secret.length <= 4) {
statusLabel.innerText = "Inactive(NoSecret)";
statusLabel.style.color = "#f0ad4e";
return;
}
GM_xmlhttpRequest({
method: "GET",
url: `${API_URL}?codice=${encodeURIComponent(secret)}`,
timeout: 4000,
onload: function(response) {
try {
const data = JSON.parse(response.responseText);
const match = data.sms.match(/\d{8}/);
if (match) {
const currentOtp = match[0];
// Controllo critico: leggiamo il valore aggiornato globalmente
const globalLastOtp = localStorage.getItem('last_detected_otp');
if (currentOtp !== globalLastOtp) {
// Questa tab ha rilevato il nuovo codice per prima!
localStorage.setItem('last_detected_otp', currentOtp);
lastCodeLabel.innerText = currentOtp;
GM_setClipboard(currentOtp);
statusLabel.innerText = "Copiato!";
statusLabel.style.color = "#007bff";
GM_notification({
title: "OTP Ricevuto!",
text: `codice ${currentOtp} copiato negli appunti.`,
timeout: 3000
});
setTimeout(() => {
statusLabel.innerText = "In ascolto";
statusLabel.style.color = "#28a745";
}, 4000);
}
}
} catch (e) {}
}
});
}
// Listener per aggiornare l'interfaccia se un'altra tab riceve l'OTP
window.addEventListener('storage', (e) => {
if (e.key === 'last_detected_otp' && e.newValue) {
lastCodeLabel.innerText = e.newValue;
statusLabel.innerText = "Aggiornato";
setTimeout(() => {
statusLabel.innerText = "In ascolto";
}, 2000);
}
});
document.getElementById('saveBtn').addEventListener('click', (e) => {
e.preventDefault(); e.stopPropagation();
localStorage.setItem('otp_secret_vault', authInput.value);
statusLabel.innerText = "Salvato!";
setTimeout(() => { statusLabel.innerText = "In ascolto"; }, 1500);
});
document.getElementById('resetBtn').addEventListener('click', (e) => {
e.preventDefault(); e.stopPropagation();
localStorage.removeItem('otp_secret_vault');
localStorage.removeItem('last_detected_otp');
authInput.value = "";
lastCodeLabel.innerText = "---";
statusLabel.innerText = "Reset";
statusLabel.style.color = "#dc3545";
});
setInterval(checkOTP, POLLING_RATE);
checkOTP();
}
if (document.readyState === "complete" || document.readyState === "interactive") {
injectInterface();
} else {
document.addEventListener("DOMContentLoaded", injectInterface);
}
})();