Автоматически вычисляет и вводит 6-значные коды двухфакторной аутентификации (2FA) для GitHub. Работает на старых браузерах без сбоев математики.
// ==UserScript==
// @name GitHub Strict Standard 2FA Auto-Fill
// @name:ru GitHub Автозаполнение 2FA
// @namespace http://tampermonkey.net
// @version 3.0
// @description 100% RFC 6238 Standard TOTP Generator
// @description:ru Автоматически вычисляет и вводит 6-значные коды двухфакторной аутентификации (2FA) для GitHub. Работает на старых браузерах без сбоев математики.
// @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgd2lkdGg9IjQ4IiBoZWlnaHQ9IjQ4Ij48cGF0aCBmaWxsPSIjMjQyOTJlIiBkPSJNOCAwQzMuNTggMCAwIDMuNTggMCA4YzAgMy41NCAyLjI5IDYuNTMgNS40NyA3LjU5LjQuMDcuNTUtLjE3LjU1LS4zOCAwLS4xOS0uMDEtLjgyLS4wMS0xLjQ5LTIuMDEuMzctMi41My0uNDktMi42OS0uOTQtLjA5LS4yMy0uNDgtMS4wMS0uODItMS4yLS4yOC0uMTUtLjY4LS41Mi0uMDEtLjUzLjYzLS4wMSAxLjA4LjU4IDEuMjMgLjgyLjcyIDEuMjEgMS44Ny44NyAyLjMzLjY2LjA3LS41Mi4yOC0uODcuNTEtMS4wNy0xLjc4LS4yLTMuNjQtLjg5LTMuNjQtMy45NSAwLS44Ny4zMS0xLjU5LjgyLTIuMTUtLjA4LS4yLS4zNi0xLjAyLjA4LTIuMTIgMCAwIC42Ny0uMjEgMi4yIC44Mi42NC0uMTggMS4zMi0uMjcgMi0uMjcuNjggMCAxLjM2LjA5IDIgLjI3IDEuNTMtMS4wNCAyLjItLjgyIDIuMi0uODIsLjQ0IDEuMS4xNiAxLjkyLjA4IDIuMTIuNTEuNTYuODIgMS4yNy44MiAyLjE1IDAgMy4wNy0xLjg3IDMuNzUtMy42NSAzLjk1LjI5LjI1LjU0LjczLjU0IDEuNDggMCAxLjA3LS4wMSAxLjkzLS4wMSAyLjIgMCAuMjEuMTUuNDYuNTUuMzhDMTMuNzEgMTQuNTMgMTYgMTEuNTMgMTYgOEMxNiAzLjU4IDEyLjQyIDAgOCAwWiIvPjwvc3ZnPg==
// @match https://github.com/sessions/two-factor*
// @match https://github.com/sessions/two-factor/app*
// @grant none
// @run-at document-end
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// ИНСТРУКЦИЯ ДЛЯ ПОЛЬЗОВАТЕЛЕЙ / INSTRUCTION:
// Вставьте ваш личный текстовый секретный ключ 2FA (2FA setup key) вместо слова "YOUR_SECRET_KEY" ниже.
// Insert your personal 2FA setup text key instead of "YOUR_SECRET_KEY" below.
var SECRET = "YOUR_SECRET_KEY";
// 1. Safe Base32 Decoder to Byte Buffer (Bypassing ESLint redeclare)
function base32ToBuf(b32) {
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
var cleaned = b32.replace(/[\s=]/g, "").toUpperCase();
var bits = "";
var idx;
for (idx = 0; idx < cleaned.length; idx++) {
var val = alphabet.indexOf(cleaned.charAt(idx));
bits += (val === -1 ? 0 : val).toString(2).padStart(5, '0');
}
var buf = new Uint8Array(Math.floor(bits.length / 8));
for (idx = 0; idx < buf.length; idx++) {
buf[idx] = parseInt(bits.substr(idx * 8, 8), 2);
}
return buf.buffer;
}
// 2. Async hardware TOTP implementation via WebCrypto API
function calculateSystemTOTP(secret32, callback) {
try {
if (!secret32 || secret32 === "YOUR_SECRET_KEY") return callback("");
var keyBuf = base32ToBuf(secret32);
var epoch = Math.floor(new Date().getTime() / 1000);
var counter = Math.floor(epoch / 30);
var idx;
var timeBuf = new Uint8Array(8);
for (idx = 7; idx >= 0; idx--) {
timeBuf[idx] = counter & 0xff;
counter = counter >> 8;
}
window.crypto.subtle.importKey(
"raw", keyBuf, { name: "HMAC", hash: { name: "SHA-1" } }, false, ["sign"]
).then(function(cryptoKey) {
return window.crypto.subtle.sign("HMAC", cryptoKey, timeBuf);
}).then(function(signature) {
var hmac = new Uint8Array(signature);
var offset = hmac[hmac.length - 1] & 0x0f;
var binary = ((hmac[offset] & 0x7f) << 24) | (hmac[offset + 1] << 16) | (hmac[offset + 2] << 8) | hmac[offset + 3];
var otp = String(binary % 1000000);
while (otp.length < 6) { otp = "0" + otp; }
callback(otp);
}).catch(function() {
callback("");
});
} catch (e) {
callback("");
}
}
// 3. Execution Block
setTimeout(function() {
var inputField = document.getElementById('app_totp') || document.getElementById('otp') || document.querySelector('input[autocomplete="one-time-code"]');
if (inputField) {
calculateSystemTOTP(SECRET, function(code) {
if (code && code.length === 6 && code !== "000000") {
inputField.value = code;
// Trigger input events for GitHub frontend scripts
var evs = ['input', 'change', 'keyup'];
evs.forEach(function(e) {
var event = document.createEvent('HTMLEvents');
event.initEvent(e, true, true);
inputField.dispatchEvent(event);
});
// Auto-submit form
setTimeout(function() {
var form = inputField.form;
if (form) {
var submitBtn = form.querySelector('button[type="submit"]') || form.querySelector('input[type="submit"]');
if (submitBtn) submitBtn.click();
else form.submit();
}
}, 200);
}
});
}
}, 600);
})();