Last active
July 29, 2023 16:14
-
-
Save lezsakdomi/d453f881a06ab668dd94d6ac65637776 to your computer and use it in GitHub Desktop.
ELTE Neptun TOTP helper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name ELTE Neptun TOTP | |
// @namespace Violentmonkey Scripts | |
// @match https://neptun.elte.hu/Account/Login2FA | |
// @grant none | |
// @version 1.3 | |
// @license MIT | |
// @author Domonkos Lezsák | |
// @description Handles ELTE Neptun TOTP 2FA authentication. The user just has to click a button and not bother with an authenticator app, as long as uses the same browser. Setup instructions: Just go to "New TOTP pairing". | |
// @updateURL https://gist.github.com/lezsakdomi/d453f881a06ab668dd94d6ac65637776/raw/a0f837b9651619254910bb2774d996aeca37eb71/elte.neptun.totp.user.js | |
// @downloadURL https://gist.github.com/lezsakdomi/d453f881a06ab668dd94d6ac65637776/raw/a0f837b9651619254910bb2774d996aeca37eb71/elte.neptun.totp.user.js | |
// @supportURL https://gist.github.com/lezsakdomi/d453f881a06ab668dd94d6ac65637776 | |
// ==/UserScript== | |
async function generateTotp() { | |
if (!window.getToken) { | |
await import('https://unpkg.com/jssha@3.3.0/dist/sha.js'); | |
const _requireBackup = window.require; | |
const _moduleBackup = window.module; | |
window.require = (pkg) => { | |
switch(pkg) { | |
case 'jssha': return window.jsSHA; | |
default: throw new Error("No module called " + pkg); | |
} | |
} | |
const module = window.module = {exports: {}} | |
await import('https://unpkg.com/totp-generator@0.0.14/index.js'); | |
window.require = _requireBackup; | |
window.module = _moduleBackup; | |
window.getToken = module.exports; | |
} | |
return window.getToken(localStorage.getItem('totp:secret')); | |
} | |
(async () => { | |
switch (location.pathname) { | |
case '/Account/Login2FA': { | |
const phase = document.querySelector('input[name="Phase"]').value; | |
document.querySelector('main > h2').insertAdjacentElement('afterend', document.createElement('pre')).innerText = phase; | |
switch (phase) { | |
case 'TOTPPreparation': { | |
document.querySelector('main form > div.form-group > button[type="submit"]').parentElement.insertAdjacentElement('beforebegin', document.createElement('p')).innerHTML = "Note: You have the TOTP userscript installed, it will substitue Microsoft Authenticatior for you. <b>Just click <i>Next</i></b>" | |
} break | |
case 'TOTPPairing': { | |
const key = document.querySelector('main form > div.form-group > button[type="submit"]').parentElement.previousElementSibling.innerText.match(/[A-Z0-9]+\s*$/)[0]; | |
if (confirm("Found TOTP pairing key " + key + ".\nDo you want to save the key to this browser?")) { | |
localStorage.setItem('totp:secret', key); | |
document.querySelector('main form').action += "?autofill_totp=1" | |
document.querySelector('main form > div.form-group > button[type="submit"]').click() | |
} | |
} break | |
case 'TOTPPairingCheck': { | |
if ((new URLSearchParams(location.search)).get('autofill_totp')) { | |
document.querySelector('main form input#TOTPCode').value = await generateTotp() | |
document.querySelector('main form > div.form-group > button[type="submit"]').click() | |
} | |
} break | |
case 'RequestTOTP': { | |
const $submitButton = document.querySelector('main form > div.form-group > button.btn-primary[type="submit"]'); | |
async function autofillAndLogin() { | |
document.querySelector('main form input#TOTPCode').value = await generateTotp() | |
$submitButton.click() | |
} | |
if ((new URLSearchParams(location.search)).get('autofill_totp')) { | |
await autofillAndLogin(); | |
} else if (localStorage.getItem('totp:secret')) { | |
{ | |
const $btn = $submitButton.insertAdjacentElement('afterend', document.createElement('button')) | |
$btn.classList.add('btn') | |
$btn.classList.add('btn-secondary') | |
$btn.style.marginLeft = '1em' | |
$btn.addEventListener('click', (evt) => { | |
localStorage.removeItem('totp:secret') | |
location.reload(); | |
}) | |
$btn.innerText = "Clear TOTP secret from this browser" | |
} | |
{ | |
const $btn = $submitButton.insertAdjacentElement('afterend', document.createElement('button')) | |
$btn.classList.add('btn') | |
$btn.classList.add('btn-primary') | |
$btn.style.marginLeft = '1em' | |
$btn.addEventListener('click', (evt) => { | |
evt.preventDefault(); | |
autofillAndLogin(); | |
}) | |
$btn.innerText = "Autofill and log in" | |
} | |
{ | |
$submitButton.classList.add('btn-secondary') | |
$submitButton.classList.remove('btn-primary') | |
} | |
} | |
} | |
} | |
} break | |
case '/Account/Login': { | |
} | |
} | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment