Files

18 lines
1.2 KiB
JavaScript

const crypto=require('node:crypto');
function totp(secret){
const alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';let bits='';for(const c of secret)bits+=alphabet.indexOf(c).toString(2).padStart(5,'0');
const bytes=[];for(let i=0;i+8<=bits.length;i+=8)bytes.push(parseInt(bits.slice(i,i+8),2));
const counter=Buffer.alloc(8);counter.writeBigUInt64BE(BigInt(Math.floor(Date.now()/30000)));
const digest=crypto.createHmac('sha1',Buffer.from(bytes)).update(counter).digest(),offset=digest[19]&15;
return String((digest.readUInt32BE(offset)&0x7fffffff)%1000000).padStart(6,'0');
}
module.exports=async function completeMfa(page,password){
if(!await page.getByRole('heading',{name:'Account security',exact:true}).count())return;
const secret=(await page.locator('pre').textContent()).trim();
await page.locator('[name=current_password]').fill(password);await page.locator('[name=mfa_code]').fill(totp(secret));
await Promise.all([page.waitForNavigation(),page.getByRole('button',{name:'Verify',exact:true}).click()]);
await page.getByRole('heading',{name:'Save your recovery codes'}).waitFor();
await Promise.all([page.waitForNavigation(),page.getByRole('link',{name:'I have saved my recovery codes'}).click()]);
};
module.exports.totp=totp;