generated from jric11/baseProject
18 lines
1.2 KiB
JavaScript
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;
|