GitHub MFA स्वचालन
परिचय
GitHub लॉगिन को स्वचालित करने में सबसे बड़ी चुनौती है दो-कारक प्रमाणीकरण (2FA)। चाहे यह ऑथेंटिकेटर ऐप (TOTP) हो या ईमेल OTP, पारंपरिक स्वचालन फ्लो आमतौर पर इन कारणों से इस चरण पर अटक जाते हैं:
- सत्यापन कोड स्वचालित रूप से प्राप्त करने में असमर्थता
- कोड को वास्तविक समय में सिंक्रनाइज़ करने में असमर्थता
- स्वचालन के माध्यम से कोड को स्वचालित रूप से इनपुट करने में असमर्थता
- ब्राउज़र वातावरण का अपर्याप्त रूप से वास्तविक होना, जिससे GitHub की सुरक्षा जाँच सक्रिय हो जाती है
यह लेख दर्शाता है कि कैसे एक पूरी तरह से स्वचालित GitHub 2FA वर्कफ़्लो बनाया जाए जिसमें Scrapeless ब्राउज़र + Signal CDP का उपयोग शामिल है, जिसमें शामिल हैं:
- स्थिति 1: GitHub 2FA (Authenticator / TOTP स्वतः-उत्पादन)
- स्थिति 2: GitHub 2FA (Email OTP स्वतः-श्रवण)
हम प्रत्येक मामले के लिए पूर्ण वर्कफ़्लो समझाएँगे और दिखाएँगे कि किसी स्वचालित सिस्टम में लॉगिन स्क्रिप्ट को सत्यापन कोड श्रोता के साथ कैसे समन्वित किया जाए।
केस 1: GitHub 2FA (ऑथेंटिकेटर OTP मोड)
GitHub की TOTP (समय-आधारित एकबारगी पासवर्ड) तंत्र स्वचालन परिदृश्यों के लिए आदर्श है। Scrapeless Browser + Signal CDP का उपयोग करके, आप ब्राउज़र को स्वचालित रूप से:
- जब यह 2FA पेज पर पहुँचे तो एक इवेंट ट्रिगर करना
- OTP कोड उत्पन्न करना
- कोड को स्वचालित रूप से भरना
- लॉगिन पूरा करना
पारंपरिक Email/SMS OTP की तुलना में, TOTP प्रदान करता है:
- बिना किसी बाहरी निर्भरता के स्थानीय रूप से उत्पन्न कोड
- तेज़ और स्थिर कोड उत्पादन
- किसी अतिरिक्त API की आवश्यकता नहीं
- मानवीय हस्तक्षेप के बिना पूर्णतः स्वचालित
लागू परिदृश्य:
- Google Authenticator / Authy / 1Password का उपयोग करने वाले GitHub अकाउंट
- 2FA पेज पथ:
/sessions/two-factor/appया/sessions/two-factor/webauthn
वीडियो

चरण 1: Scrapeless Browser से कनेक्ट करें
इस चरण में, हम Scrapeless Browser से एक फुल-डुप्लेक्स WebSocket कनेक्शन स्थापित करते हैं:
import puppeteer from 'puppeteer-core';
const query = new URLSearchParams({
token: "",
proxyCountry: "ANY",
sessionRecording: true,
sessionTTL: 900,
sessionName: "Data Scraping",
});
const connectionURL = `wss://browser.scrapeless.com/api/v2/browser?${query.toString()}`;
const browserWSEndpoint = connectionURL;
const browser = await puppeteer.connect({ browserWSEndpoint });
console.log("✅ Connected to Scrapeless Browser");लाभ:
- क्लाउड में वास्तविक Chrome, मजबूत एंटी-डिटेक्शन के साथ
- स्थानीय संसाधनों की खपत नहीं करता
- स्वचालित प्रॉक्सी, दृढ़ता, और सेशन रिकॉर्डिंग
- बड़े पैमाने के स्वचालित लॉगिन वर्कफ़्लो का विश्वसनीय निष्पादन
चरण 2: MFA Manager + TOTP Provider प्रारंभ करें
MFA को Signal CDP द्विदिश द्वारा संभाला जाता है, जो:
- 2FA पेज का पता चलने पर स्वचालित रूप से
mfa_code_requestभेजता है - TOTP कोड उत्पन्न करता है
- कोड्स वापस करता है
mfa_code_response - लॉगिन परिणाम इवेंट भेजता है
import { authenticator } from 'otplib';
const TOTP_SECRETS = {
'github': 'secret-code',
'default': 'secret-code'
};
authenticator.options = {
digits: 6,
step: 30,
window: 1
};चरण 3: MFA Manager बनाएँ
यहाँ, हम Signal CDP के साथ संचार संभालने के लिए एक केंद्रीकृत MFA मैनेजर बनाते हैं:
- ट्रिगर करें
mfa_code_request - सत्यापन कोड (
mfa_code_response) की प्रतीक्षा करना और प्राप्त करना - कोड को GitHub लॉगिन प्रक्रिया में लौटाना
- अंतिम लॉगिन परिणाम इवेंट भेजना
class MFAManager {
constructor() {
this.client = null;
}
setClient(client) {
this.client = client;
}
async sendMFARequest(username, provider = 'github') {
const requestData = {
type: 'mfa_required',
provider,
username,
timestamp: new Date().toISOString(),
service: 'github_2fa'
};
return await this.client.send('Signal.send', {
event: 'mfa_code_request',
data: JSON.stringify(requestData)
});
}
async waitForMFACode(timeout = 120000) {
const result = await this.client.send('Signal.wait', {
event: 'mfa_code_response',
timeout
});
if (result.status === 200 && result.data) {
return JSON.parse(result.data).code;
} else if (result.status === 408) {
throw new Error('Waiting for MFA code timed out');
} else {
throw new Error(`Signal wait failed, status: ${result.status}`);
}
}
async sendMFAResponse(code, username) {
const responseData = {
code,
username,
timestamp: new Date().toISOString(),
status: 'code_provided'
};
return await this.client.send('Signal.send', {
event: 'mfa_code_response',
data: JSON.stringify(responseData)
});
}
async sendLoginResult(success, username, url, error = null) {
const resultData = {
success,
username,
url,
timestamp: new Date().toISOString(),
error
};
await this.client.send('Signal.send', {
event: 'github_login_result',
data: JSON.stringify(resultData)
});
}
}लाभ:
- पूर्णतः स्वचालित 2FA वर्कफ़्लो (अनुरोध → प्रतीक्षा → प्राप्ति → भरना)
- कई प्रमाणीकरण विधियों (TOTP/Email/Push) का एकीकृत प्रबंधन
- स्क्रिप्ट में दोहराए जाने वाले 2FA लॉजिक को समाप्त करता है
चरण 4: TOTP Code Provider प्रारंभ करें (कोड के श्रवण और स्वतः-भरने को संभालता है)
इस चरण में, हम TOTP ऑटो-कोड लिसनर को लॉन्च करते हैं, जो:
- लगातार
mfa_code_requestevents के लिए सुनता रहता है - स्वचालित रूप से TOTP कोड उत्पन्न करता है (उपयोग करके
otplib) - Signal (
mfa_code_response) के माध्यम से स्वचालित रूप से कोड वापस भेजता है - मैन्युअल कोड प्रविष्टि को पूरी तरह से प्रतिस्थापित करता है
class TOTPCodeProvider {
constructor(mfaManager) {
this.mfaManager = mfaManager;
this.isListening = false;
this.secrets = TOTP_SECRETS;
}
async startListening() {
if (this.isListening) return;
this.isListening = true;
this.listenLoop();
}
async listenLoop() {
while (this.isListening) {
try {
const result = await this.mfaManager.client.send('Signal.wait', {
event: 'mfa_code_request',
timeout: 5000
});
if (result.status === 200 && result.data) {
const requestData = JSON.parse(result.data);
await this.handleMFARequest(requestData);
}
} catch (err) {}
await new Promise(r => setTimeout(r, 100));
}
}
async handleMFARequest(requestData) {
const code = this.generateTOTPCode(requestData.provider);
await this.mfaManager.sendMFAResponse(code, requestData.username);
console.log(`✅ TOTP code sent via Signal CDP: ${code}`);
}
generateTOTPCode(service = 'github') {
const secret = this.secrets[service] || this.secrets.default;
return authenticator.generate(secret);
}
}लाभ:
- मैन्युअल प्रविष्टि के बिना 2FA को पूर्णतः स्वचालित करता है
- किसी ईमेल या मोबाइल ऐप की आवश्यकता नहीं
- TOTP उत्पादन सटीक, स्थिर, और स्केलेबल है
- GitHub, AWS, Azure, Google, और किसी भी TOTP-आधारित प्रदाता का समर्थन करता है
चरण 5: GitHub लॉगिन पेज पर जाएँ और क्रेडेंशियल दर्ज करें
यह चरण GitHub लॉगिन प्रवाह के पहले भाग को संभालता है:
लॉगिन पेज खोलें → उपयोगकर्ता नाम और पासवर्ड दर्ज करें → अगले चरण पर आगे बढ़ें (2FA या सीधे लॉगिन)
await page.goto('https://github.com/login', { waitUntil: 'networkidle2' });
await page.waitForSelector('#login_field', { timeout: 10000 });
await page.type('#login_field', githubCredentials.username);
await page.type('#password', githubCredentials.password);
await page.click('input[type="submit"][value="Sign in"]');लाभ:
- Scrapeless Browser का उपयोग करने से एक वास्तविक, स्थिर ब्राउज़र वातावरण सुनिश्चित होता है
- स्वचालित टाइपिंग वास्तविक उपयोगकर्ता व्यवहार का अनुकरण करती है, GitHub सुरक्षा फ़्लैग से बचती है
- सही 2FA पेज पर नेविगेशन की गारंटी देता है
चरण 6: 2FA पेज का पता लगाएँ और TOTP स्वतः-सबमिट करें
if (currentUrl.includes('/sessions/two-factor')) {
console.log('🔐 Detected 2FA required');
await mfaManager.sendMFARequest(githubCredentials.username, 'github');
const mfaCode = await mfaManager.waitForMFACode(120000);
await page.waitForSelector('#app_totp');
await page.type('#app_totp', mfaCode);
await new Promise(resolve => setTimeout(resolve, 5000));
}लाभ:
- किसी भी मानवीय हस्तक्षेप के बिना GitHub 2FA पूरा करता है
- TOTP स्वतः-उत्पन्न होता है, ईमेल कोड से होने वाली देरी से बचता है
- Signal CDP द्विदिश संचार सटीक कोड वितरण सुनिश्चित करता है
- एंटरप्राइज़-स्तरीय स्थिरता और विश्वसनीयता
चरण 7: Signal CDP के माध्यम से लॉगिन परिणाम भेजें
GitHub लॉगिन + 2FA पूरा होने के बाद, अंतिम लॉगिन परिणाम CDP (Signal.send) के माध्यम से आपके स्वचालन वर्कफ़्लो को भेजा जाता है। इससे आपका बैकएंड, बॉट, या CI/CD सिस्टम वास्तविक समय में जान सकता है कि लॉगिन सफल हुआ या नहीं।
const isLoggedIn = !finalUrl.includes('/sessions/two-factor')
&& !finalUrl.includes('/login');
await mfaManager.sendLoginResult(isLoggedIn, githubCredentials.username, finalUrl);संपूर्ण कोड
import puppeteer from 'puppeteer-core';
import {authenticator} from 'otplib';
const query = new URLSearchParams({
token: "api-key",
proxyCountry: "ANY",
sessionRecording: true,
sessionTTL: 900,
sessionName: "GithubLogin",
});
const browserWSEndpoint = `wss://browser.scrapeless.com/api/v2/browser?${query.toString()}`;
// TOTP secrets
const TOTP_SECRETS = {
'github': 'secret-code',
'default': 'secret-code'
};
// Configure TOTP
authenticator.options = {digits: 6, step: 30, window: 1};
// MFA Manager
class MFAManager {
constructor() {
this.client = null;
}
setClient(client) {
this.client = client;
}
async sendMFARequest(username, provider = 'github') {
return await this.client.send('Signal.send', {
event: 'mfa_code_request',
data: JSON.stringify({
type: 'mfa_required',
provider,
username,
timestamp: new Date().toISOString(),
service: 'github_2fa'
})
});
}
async waitForMFACode(timeout = 120000) {
const result = await this.client.send('Signal.wait', {
event: 'mfa_code_response',
timeout
});
if (result.status === 200 && result.data) {
return JSON.parse(result.data).code;
} else if (result.status === 408) {
throw new Error('Timeout waiting for MFA code');
} else {
throw new Error(`Signal wait failed, status: ${result.status}`);
}
}
async sendMFAResponse(code, username) {
return await this.client.send('Signal.send', {
event: 'mfa_code_response',
data: JSON.stringify({code, username, timestamp: new Date().toISOString(), status: 'code_provided'})
});
}
async sendLoginResult(success, username, url, error = null) {
await this.client.send('Signal.send', {
event: 'github_login_result',
data: JSON.stringify({success, username, url, timestamp: new Date().toISOString(), error})
});
}
}
// TOTP provider
class TOTPCodeProvider {
constructor(mfaManager) {
this.mfaManager = mfaManager;
this.isListening = false;
this.secrets = TOTP_SECRETS;
}
async startListening() {
if (this.isListening) return;
this.isListening = true;
this.listenLoop();
}
async listenLoop() {
while (this.isListening) {
try {
const result = await this.mfaManager.client.send('Signal.wait', {
event: 'mfa_code_request',
timeout: 5000
});
if (result.status === 200 && result.data) {
const requestData = JSON.parse(result.data);
await this.handleMFARequest(requestData);
}
} catch (error) {
}
await new Promise(resolve => setTimeout(resolve, 100));
}
}
async handleMFARequest(requestData) {
try {
const code = this.generateTOTPCode(requestData.provider);
if (code) {
await this.mfaManager.sendMFAResponse(code, requestData.username);
console.log(`✅ TOTP code sent via Signal CDP: ${code}`);
} else {
await this.sendErrorResponse(requestData.username, 'Unable to generate TOTP code');
}
} catch (error) {
await this.sendErrorResponse(requestData.username, error.message);
}
}
generateTOTPCode(service = 'github') {
const secret = this.getSecretForService(service);
if (!secret) throw new Error(`No TOTP secret found for ${service}`);
const token = authenticator.generate(secret);
if (!token || token.length !== 6 || isNaN(token)) {
throw new Error(`Invalid TOTP token generated: ${token}`);
}
return token;
}
getSecretForService(service) {
if (this.secrets[service]) return this.secrets[service];
const lower = service.toLowerCase();
if (this.secrets[lower]) return this.secrets[lower];
if (this.secrets.default) return this.secrets.default;
return null;
}
async sendErrorResponse(username, errorMessage) {
await this.mfaManager.client.send('Signal.send', {
event: 'mfa_code_error',
data: JSON.stringify({username, error: errorMessage, timestamp: new Date().toISOString()})
});
}
stopListening() {
this.isListening = false;
}
}
// GitHub credentials
const githubCredentials = {
username: "***@gmail.com",
password: "****"
};
// Main login flow
async function githubLoginWithAutoMFA() {
let browser, page, codeProvider;
try {
console.log("🚀 Starting GitHub login flow...");
browser = await puppeteer.connect({browserWSEndpoint});
const pages = await browser.pages();
page = pages.length > 0 ? pages[0] : await browser.newPage();
const client = await page.target().createCDPSession();
const mfaManager = new MFAManager();
mfaManager.setClient(client);
codeProvider = new TOTPCodeProvider(mfaManager);
await codeProvider.startListening();
page.setDefaultTimeout(30000);
page.setDefaultNavigationTimeout(30000);
await page.goto('https://github.com/login', {waitUntil: 'networkidle2'});
await page.waitForSelector('#login_field, input[name="login"]', {timeout: 10000});
await page.type('#login_field', githubCredentials.username);
await page.type('#password', githubCredentials.password);
await page.click('input[type="submit"][value="Sign in"]');
await new Promise(resolve => setTimeout(resolve, 3000));
const currentUrl = page.url();
if (currentUrl.includes('/sessions/two-factor')) {
console.log('🔐 2FA required detected');
await mfaManager.sendMFARequest(githubCredentials.username, 'github');
if (currentUrl.includes('/sessions/two-factor/webauthn')) {
const moreOptionsButton = await page.$('.more-options-two-factor');
if (moreOptionsButton) {
await moreOptionsButton.click();
await new Promise(resolve => setTimeout(resolve, 1000));
}
const authAppLink = await page.$('a[href="/sessions/two-factor/app"]');
if (authAppLink) {
await authAppLink.click();
await page.waitForNavigation({waitUntil: 'networkidle2'});
}
}
if (page.url().includes('/sessions/two-factor/app')) {
const mfaCode = await mfaManager.waitForMFACode(120000);
await page.waitForSelector('#app_totp', {timeout: 10000});
await page.click('#app_totp', {clickCount: 3});
await page.type('#app_totp', mfaCode);
await new Promise(resolve => setTimeout(resolve, 5000));
const finalUrl = page.url();
const isLoggedIn = !finalUrl.includes('/sessions/two-factor') &&
!finalUrl.includes('/login') &&
(finalUrl.includes('github.com') || finalUrl === 'https://github.com/');
await mfaManager.sendLoginResult(isLoggedIn, githubCredentials.username, finalUrl);
if (isLoggedIn) {
console.log('🎉 GitHub login successful!');
await page.goto('https://github.com/', {waitUntil: 'networkidle2', timeout: 10000});
} else {
console.log('❌ Login failed');
}
}
} else if (currentUrl.includes('github.com') && !currentUrl.includes('/login')) {
console.log('✅ Login successful (no 2FA)');
await mfaManager.sendLoginResult(true, githubCredentials.username, currentUrl);
} else {
console.log('❌ Login failed, still on login page');
await mfaManager.sendLoginResult(false, githubCredentials.username, currentUrl, 'Login failed');
}
} catch (error) {
console.error('❌ GitHub login flow failed:', error);
try {
if (page) {
const client = await page.target().createCDPSession();
const mfaManager = new MFAManager();
mfaManager.setClient(client);
await mfaManager.sendLoginResult(false, githubCredentials.username, page.url() || 'unknown', error.message);
}
} catch (signalError) {
console.error('❌ Failed to send error signal:', signalError);
}
} finally {
if (codeProvider) codeProvider.stopListening();
if (browser) await browser.close();
console.log('🔚 GitHub login script finished');
}
}
githubLoginWithAutoMFA().catch(console.error);केस 2: GitHub 2FA (ईमेल OTP मोड)
उद्यम वातावरण में 2FA का सबसे आम प्रकार ईमेल OTP के माध्यम से मल्टी-फैक्टर ऑथेंटिकेशन (MFA) है।
निम्न पर लागू:
- MFA सक्षम और ईमेल सत्यापन बाउंड किए हुए GitHub
- Email सत्यापन की आवश्यकता वाली GitHub सुरक्षा नीतियाँ
वीडियो

चरण 1: Scrapeless Browser से कनेक्ट करें
import puppeteer from 'puppeteer-core';
const query = new URLSearchParams({
token: "",
proxyCountry: "ANY",
sessionRecording: true,
sessionTTL: 900,
sessionName: "Data Scraping",
});
const connectionURL = `wss://browser.scrapeless.com/api/v2/browser?${query.toString()}`;
const browserWSEndpoint = connectionURL;लाभ:
- रिमोट ब्राउज़र निष्पादन, कोई स्थानीय संसाधन खपत नहीं
sessionRecordingरीप्ले और ऑडिटिंग को सुगम बनाता है- Signal के साथ द्विदिश वास्तविक-समय संचार का समर्थन करता है
चरण 2: GitHub खोलें और क्रेडेंशियल दर्ज करें
const githubCredentials = {
username: "1040111453@qq.com",
password: "shijee1218",
twoFactorCode: null
};
const browser = await puppeteer.connect({ browserWSEndpoint });
const pages = await browser.pages();
const page = pages.length > 0 ? pages[0] : await browser.newPage();
page.setDefaultTimeout(30000);
page.setDefaultNavigationTimeout(30000);
await page.goto('https://github.com/login', { waitUntil: 'networkidle2' });
await page.waitForSelector('#login_field', { timeout: 10000 });लाभ:
- GitHub सुरक्षा को सक्रिय होने से बचाने के लिए वास्तविक उपयोगकर्ता इनपुट का सटीक अनुकरण करता है
- पेज रेंडरिंग की स्वचालित रूप से प्रतीक्षा करता है, स्क्रिप्ट स्थिरता में सुधार करता है
- नेटवर्क उतार-चढ़ाव को संभालने के लिए लंबी टाइमआउट सेटिंग्स का समर्थन करता है
चरण 3: पता लगाएँ कि Email 2FA पेज लोड हुआ या नहीं
const currentUrl = page.url();
if (currentUrl.includes('/sessions/verified-device')) {
const client = await page.target().createCDPSession();
// Send Signal notification to email listener to prepare for OTP
await client.send('Signal.send', {
event: 'github_2fa_required',
data: JSON.stringify({ status: '2fa_required', timestamp: new Date().toISOString() })
});
// Wait for email listener to return OTP
const twoFactorResult = await client.send('Signal.wait', {
event: 'github_2fa_code',
timeout: 120000
});लाभ:
- सटीक रूप से पहचानता है
/sessions/verified-devicepage - OTP के लिए तैयारी हेतु ईमेल श्रोता को सक्रिय रूप से सूचित करता है
- वास्तविक-समय ईमेल OTP की प्रतीक्षा का समर्थन करता है, स्वचालन सफलता दर में सुधार करता है
चरण 4: Email श्रोता OTP भेजता है
Signal उदाहरण:
{
"event": "github_2fa_code",
"data": { "code": "123456" }
}लाभ:
- स्वचालित रूप से ईमेल पढ़ता है
- स्वचालित रूप से GitHub OTP (6-अंकीय कोड) निकालता है
- वास्तविक समय में Scrapeless Browser को Signal भेजता है, किसी मैन्युअल संचालन की आवश्यकता नहीं
चरण 5: OTP दर्ज करें और सबमिट करें
if (twoFactorResult.status === 200 && twoFactorResult.data) {
const twoFactorData = JSON.parse(twoFactorResult.data);
githubCredentials.twoFactorCode = twoFactorData.code;
if (!page.url().includes('/sessions/verified-device')) return;
await page.$eval('#otp', (input) => { input.value = ''; });
await page.type('#otp', githubCredentials.twoFactorCode);
await page.evaluate(() => {
const button = document.querySelector('button[type="submit"]');
if (button) button.click();
});
await new Promise(resolve => setTimeout(resolve, 5000));
}लाभ:
- स्वचालित रूप से OTP भरता है, स्वचालन दक्षता में सुधार करता है
- सुनिश्चित करता है कि पेज अभी भी 2FA स्थिति में है, नेविगेशन त्रुटियों को रोकता है
- वास्तविक क्लिक क्रियाओं का अनुकरण करता है, सुरक्षा जाँच सक्रिय होने के जोखिम को कम करता है
चरण 6: अंतिम लॉगिन परिणाम की जाँच करें और Signal भेजें
const finalUrl = page.url();
const isLoggedIn =
!finalUrl.includes('/sessions/verified-device') &&
!finalUrl.includes('/login') &&
(finalUrl.includes('github.com') || finalUrl === 'https://github.com/');
await client.send('Signal.send', {
event: 'github_login_result',
data: JSON.stringify({
success: isLoggedIn,
username: githubCredentials.username,
url: finalUrl,
twoFactorCode: githubCredentials.twoFactorCode,
timestamp: new Date().toISOString()
})
});
if (isLoggedIn) await page.goto('https://github.com/', { waitUntil: 'networkidle2' });लाभ:
- गलत निर्णय से बचता है, सुनिश्चित करता है कि पेज ने सफलतापूर्वक लॉगिन कर लिया है
- सत्यापन के लिए स्वचालित रूप से GitHub होमपेज पर नेविगेट करता है, विश्वसनीयता में सुधार करता है
- लॉगिन परिणाम को वास्तविक समय में CI/CD या बॉट सिस्टम को रिपोर्ट किया जा सकता है
चरण 7: सेशन बनाए रखें और ब्राउज़र बंद करें
await new Promise(resolve => setTimeout(resolve, 5000));
await browser.close();लाभ:
- सुनिश्चित करता है कि सभी Signal इवेंट भेजे जा चुके हैं
- बाद की कार्रवाइयों के लिए सेशन को पर्याप्त समय तक सक्रिय रखता है
- संसाधन रिसाव को रोकने के लिए ब्राउज़र बंद करता है
संपूर्ण कोड
- सबसे पहले, आपको इस स्क्रिप्ट का उपयोग GitHub लॉगिन पेज पर उपयोगकर्ता नाम और पासवर्ड भरने और लॉगिन लॉजिक को निष्पादित करने के लिए करना होगा, और Email सत्यापन विंडो पर OTP इनपुट की प्रतीक्षा करनी होगी।
ब्राउज़र सेशन टास्क बनने पर आपको एक taskId मिलेगा, कृपया इसे याद रखें क्योंकि अगले चरण में आपको इसकी आवश्यकता होगी।
import puppeteer from 'puppeteer-core';
const token = "api-key";
const query = new URLSearchParams({
token,
proxyCountry: "ANY",
sessionRecording: true,
sessionTTL: 900,
sessionName: "Data Scraping",
});
const createBrowserSessionURL = `https://browser.scrapeless.com/api/v2/browser?${query.toString()}`;
// Get session taskId via HTTP API
const sessionResponse = await fetch(createBrowserSessionURL);
const {taskId} = await sessionResponse.json();
console.log('Session created with task ID:', taskId);
const browserWSEndpoint = `wss://api.scrapeless.com/browser/${taskId}?x-api-key=${token}`;
async function githubLoginWith2FA() {
const browser = await puppeteer.connect({browserWSEndpoint});
let page;
try {
console.log("🚀 Starting GitHub login process...");
const githubCredentials = {
username: "****@gmail.com",
password: "******",
twoFactorCode: null
};
const pages = await browser.pages();
page = pages.length > 0 ? pages[0] : await browser.newPage();
page.setDefaultTimeout(30000);
page.setDefaultNavigationTimeout(30000);
console.log('📱 Navigating to GitHub login page...');
await page.goto('https://github.com/login', {waitUntil: 'networkidle2'});
// Wait for the login form to load
await page.waitForSelector('#login_field', {timeout: 10000});
console.log('🔑 Typing username and password...');
await page.type('#login_field', githubCredentials.username);
await page.type('#password', githubCredentials.password);
// Click the sign in button
console.log('🖱️ Clicking the sign in button...');
await page.click('input[type="submit"][value="Sign in"]');
// use setTimeout instead of waitForTimeout
console.log('⏳ Waiting for page response...');
await new Promise(resolve => setTimeout(resolve, 3000));
// Check whether an email verification (2FA) is required
const currentUrl = page.url();
console.log(`🔍 Current URL: ${currentUrl}`);
if (currentUrl.includes('/sessions/verified-device')) {
console.log('🔐 Detected email verification required, waiting for verification code...');
const client = await page.target().createCDPSession();
// send signal notifying that email verification code is required
await client.send('Signal.send', {
event: 'github_2fa_required',
data: JSON.stringify({
status: '2fa_required',
timestamp: new Date().toISOString()
})
});
// Wait to receive the email verification code
console.log('⏳ Waiting for the email verification code...');
const twoFactorResult = await client.send('Signal.wait', {
event: 'github_2fa_code',
timeout: 120000
});
if (twoFactorResult.status === 200 && twoFactorResult.data) {
const twoFactorData = JSON.parse(twoFactorResult.data);
githubCredentials.twoFactorCode = twoFactorData.code;
console.log(`✅ Received email verification code: ${githubCredentials.twoFactorCode}, entering code...`);
// Ensure we are still on the verification page
if (!page.url().includes('/sessions/verified-device')) {
console.log('⚠️ The page has navigated away, verification may no longer be required');
return;
}
// Enter the verification code
console.log('⌨️ Entering the verification code...');
await page.$eval('#otp', (input, code) => {
input.value = '';
}, githubCredentials.twoFactorCode);
await page.type('#otp', githubCredentials.twoFactorCode);
console.log(`✅ Verification code ${githubCredentials.twoFactorCode} has been entered`);
// Click the verify button
console.log('🖱️ Clicking the verify button...');
try {
await page.evaluate(() => {
const button = document.querySelector('button[type="submit"]');
if (button) button.click();
});
console.log('✅ Verify button clicked, waiting for page response...');
await new Promise(resolve => setTimeout(resolve, 5000));
} catch (clickError) {
console.log('⚠️ Problem clicking the button:', clickError.message);
}
// Check login result
await new Promise(resolve => setTimeout(resolve, 3000));
const finalUrl = page.url();
console.log(`🔍 Final URL: ${finalUrl}`);
const isLoggedIn = !finalUrl.includes('/sessions/verified-device') &&
!finalUrl.includes('/login') &&
(finalUrl.includes('github.com') || finalUrl === 'https://github.com/');
// send login result signal
if (client) {
await client.send('Signal.send', {
event: 'github_login_result',
data: JSON.stringify({
success: isLoggedIn,
username: githubCredentials.username,
url: finalUrl,
twoFactorCode: githubCredentials.twoFactorCode,
timestamp: new Date().toISOString()
})
});
}
if (isLoggedIn) {
console.log('🎉 GitHub login successful!');
try {
await page.goto('https://github.com/', {
waitUntil: 'networkidle2',
timeout: 10000
});
console.log('✅ Successfully accessed GitHub homepage');
} catch (profileError) {
console.log('⚠️ Problem accessing homepage:', profileError.message);
}
} else {
console.log('❌ Email verification failed, login unsuccessful');
console.log('🔍 Current page title:', await page.title());
}
} else {
console.log('❌ Timed out waiting for the email verification code');
}
} else if (currentUrl.includes('github.com') && !currentUrl.includes('/login')) {
// No email verification required
console.log('✅ Login successful (no email verification required)');
const client = await page.target().createCDPSession();
await client.send('Signal.send', {
event: 'github_login_result',
data: JSON.stringify({
success: true,
username: githubCredentials.username,
url: currentUrl,
timestamp: new Date().toISOString()
})
});
} else {
console.log('❌ Login failed, still on the login page');
console.log('🔍 Current page title:', await page.title());
}
// Keep the session for a short time
console.log('⏳ Keeping connection for 5 seconds...');
await new Promise(resolve => setTimeout(resolve, 5000));
} catch (error) {
console.error('❌ GitHub login process failed:', error);
try {
const pages = await browser.pages();
const currentPage = pages.length > 0 ? pages[0] : page;
if (currentPage) {
const errorClient = await currentPage.target().createCDPSession();
await errorClient.send('Signal.send', {
event: 'github_login_error',
data: JSON.stringify({
error: error.message,
timestamp: new Date().toISOString()
})
});
}
} catch (signalError) {
console.error('❌ Failed to send error signal as well:', signalError);
}
} finally {
if (browser) await browser.close();
console.log('🔚 GitHub login script finished');
}
}
// Run the script
githubLoginWith2FA().catch(console.error);
- जब उपरोक्त स्क्रिप्ट सत्यापन कोड की प्रतीक्षा करने वाले पेज पर पहुँच जाए, तो तुरंत इस ईमेल श्रोता स्क्रिप्ट को चलाएँ, जो सत्यापन पूरा करने के लिए नवीनतम कोड को मुख्य स्क्रिप्ट को भेजेगी।
import Imap from 'imap';
import {simpleParser} from 'mailparser';
const CONFIG = {
imap: {
user: "****@gmail.com",
password: "****",
host: "mail.privateemail.com",
port: 993,
tls: true,
tlsOptions: {rejectUnauthorized: false}
},
signal: {
baseUrl: "https://browser.scrapeless.com",
apiKey: "api-key"
},
checkInterval: 5000,
maxWaitTime: 120000
};
class EmailListener {
constructor() {
this.imap = null;
this.isListening = false;
this.sessionId = null;
}
async start(sessionId) {
console.log('Starting email listener...');
this.sessionId = sessionId;
try {
await this.connectIMAP();
const code = await this.listenForCode();
if (code) {
console.log(`Found code: ${code}`);
await this.sendSignal('github_2fa_code', {code});
console.log('Code sent to browser');
} else {
console.log('No code found (timeout)');
await this.sendSignal('email_listener_timeout', {status: 'timeout'});
}
} catch (error) {
console.error('Listener error:', error.message || error);
} finally {
await this.cleanup();
}
}
connectIMAP() {
return new Promise((resolve, reject) => {
this.imap = new Imap(CONFIG.imap);
this.imap.once('ready', () => {
console.log('IMAP connected');
resolve();
});
this.imap.once('error', reject);
this.imap.connect();
});
}
async listenForCode() {
console.log('Listening for GitHub verification code...');
this.isListening = true;
const startTime = Date.now();
while (this.isListening && (Date.now() - startTime) < CONFIG.maxWaitTime) {
try {
const code = await this.checkEmails();
if (code) return code;
await new Promise(resolve => setTimeout(resolve, CONFIG.checkInterval));
} catch (error) {
console.error('checkEmails failed:', error.message || error);
await new Promise(resolve => setTimeout(resolve, 10000));
}
}
return null;
}
checkEmails() {
return new Promise((resolve, reject) => {
this.imap.openBox('INBOX', false, (err, box) => {
if (err) return reject(err);
const criteria = ['UNSEEN', ['FROM', '****@github.com']];
this.imap.search(criteria, (err, results) => {
if (err) return reject(err);
if (!results || results.length === 0) return resolve(null);
this.processEmails(results, resolve, reject);
});
});
});
}
processEmails(results, resolve, reject) {
const fetcher = this.imap.fetch(results, {
bodies: ['TEXT'],
markSeen: true
});
let processed = 0;
let foundCode = null;
fetcher.on('message', (msg) => {
let buffer = '';
msg.on('body', (stream) => {
stream.on('data', (chunk) => buffer += chunk.toString('utf8'));
});
msg.once('end', async () => {
try {
const mail = await simpleParser(buffer);
const code = this.extractCode(mail.text || '');
if (code) foundCode = code;
} catch (error) {
console.error('Failed to parse mail:', error);
}
processed++;
if (processed === results.length) resolve(foundCode);
});
});
fetcher.once('error', reject);
}
extractCode(text) {
const patterns = [
/verification code:?\s*(\d{6})/i,
/verification code:?\s*(\d{6})/i,
/code:?\s*(\d{6})/i,
/GitHub verification code:?\s*(\d{6})/i
];
for (const pattern of patterns) {
const match = text.match(pattern);
if (match) return match[1];
}
const digitMatch = text.match(/\b\d{6}\b/);
return digitMatch ? digitMatch[0] : null;
}
// Send signal via HTTP, sessionId as parameter
async sendSignal(event, data, sessionId = this.sessionId) {
if (!sessionId) throw new Error('Session ID not available');
try {
const url = `${CONFIG.signal.baseUrl}/browser/${sessionId}/signal/send`;
const response = await fetch(url, {
method: 'POST',
headers: {
'content-type': 'application/json',
'token': CONFIG.signal.apiKey
},
body: JSON.stringify({event, data})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
console.log('Signal sent successfully:', result);
return result;
} catch (err) {
console.error('Failed to send signal via HTTP:', err);
throw err;
}
}
async cleanup() {
this.isListening = false;
if (this.imap) {
try {
this.imap.end();
console.log('IMAP connection closed');
} catch (e) {
console.error('Error closing IMAP:', e);
}
}
this.sessionId = null;
}
}
const listener = new EmailListener();
listener.start({taskId}).then(); // Replace with taskId from the first step
उपरोक्त दो GitHub लॉगिन उदाहरणों के माध्यम से, हम प्रदर्शित करते हैं कि एंटरप्राइज़ वातावरण में कुशल और स्थिर स्वचालित लॉगिन कैसे प्राप्त करें, जिसमें दो सामान्य 2FA मोड शामिल हैं: TOTP और Email सत्यापन कोड। Scrapeless Browser + Signal CDP का उपयोग करके, आप वास्तविक ब्राउज़र संचालन कर सकते हैं, उपयोगकर्ता व्यवहार का सटीक अनुकरण कर सकते हैं, और MFA सिस्टम तथा ईमेल श्रोताओं के साथ वास्तविक समय में इंटरैक्ट करके सत्यापन कोड को स्वचालित रूप से प्राप्त और सबमिट कर सकते हैं। चाहे स्वचालित लॉगिन वर्कफ़्लो विकसित करना हो, CI/CD सिस्टम के साथ एकीकृत करना हो, या एंटरप्राइज़ के आंतरिक अकाउंट प्रबंधित करना हो, यह समाधान लॉगिन सफलता दर को उल्लेखनीय रूप से बढ़ा सकता है, मैन्युअल हस्तक्षेप को कम कर सकता है, और पूर्ण संचालन ऑडिटिंग तथा मॉनिटरिंग प्रदान कर सकता है।