Skip to content

Instantly share code, notes, and snippets.

@djsmith42
Last active January 29, 2024 15:30
Show Gist options
  • Save djsmith42/aa407f91a82a9b86cb4e5550c0b90e3b to your computer and use it in GitHub Desktop.
Save djsmith42/aa407f91a82a9b86cb4e5550c0b90e3b to your computer and use it in GitHub Desktop.
ObservePoint Pre-audit action for TOTP tokens for MFA/2FA
const TOTP_KEY = 'Pate your TOTP key here. Example: 5ep5abbzomzpen2fpti6hhyu5i'
const CSS_SELECTOR = 'Paste your CSS selector here for the TOTP token input. Example: #totp_token'
// ----------------------------------------------------------------------------
// Do not change code below this line
// ----------------------------------------------------------------------------
totp(TOTP_KEY).then(token => {
const element = document.querySelector(CSS_SELECTOR)
if (element) {
console.log('Entering TOTP token', token, 'into element')
element.value = token
} else {
throw new Error('Could not find element with CSS selector: ' + CSS_SELECTOR)
}
})
async function totp(key, secs = 30, digits = 6){
return hotp(unbase32(key), pack64bu(Date.now() / 1000 / secs), digits);
}
async function hotp(key, counter, digits){
if(!window.crypto) throw Error('The web crypto API is not available');
let y = window.crypto.subtle;
if(!y) throw Error('The wep crypto API crypto.subtle object is not available');
let k = await y.importKey('raw', key, {name: 'HMAC', hash: 'SHA-1'}, false, ['sign']);
return hotp_truncate(await y.sign('HMAC', k, counter), digits);
}
function hotp_truncate(buf, digits){
let a = new Uint8Array(buf), i = a[19] & 0xf;
return fmt(10, digits, ((a[i]&0x7f)<<24 | a[i+1]<<16 | a[i+2]<<8 | a[i+3]) % 10**digits);
}
function fmt(base, width, num){
return num.toString(base).padStart(width, '0')
}
function unbase32(s){
let t = (s.toLowerCase().match(/\S/g)||[]).map(c => {
let i = 'abcdefghijklmnopqrstuvwxyz234567'.indexOf(c);
if(i < 0) throw Error(`bad char '${c}' in key`);
return fmt(2, 5, i);
}).join('');
if(t.length < 8) throw Error('key too short');
return new Uint8Array(t.match(/.{8}/g).map(d => parseInt(d, 2)));
}
function pack64bu(v){
let b = new ArrayBuffer(8), d = new DataView(b);
d.setUint32(0, v / 2**32);
d.setUint32(4, v);
return b;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment