Node-RED में function node से कैप्चा कैसे हल करें

node-red captcha - How to Solve CAPTCHAs in Node-RED With a Function Node

Node-RED में कैप्चा वाला step दो nodes का होता है अगर आप raw API से जाते हैं, या एक ही function node का अगर आप पाँच लाइन JavaScript लिखना पसंद करें। दोनों एक ऐसे सॉल्वर को कॉल करते हैं जो आपके अपने हार्डवेयर पर चलता है, इसलिए दोनों में से कोई भी प्रति हल के हिसाब से मीटर नहीं करता। लोग जहाँ अटकते हैं वह हल करना नहीं है। असली बात यह है कि कोई function node तब तक npm package require नहीं कर सकता जब तक आप settings.js में यह चालू न करें, और यह कि Node-RED अक्सर किसी Raspberry Pi पर चलता है जबकि सॉल्वर वहाँ नहीं चलता।

आपको क्या चाहिए

  • Node-RED 3 या उससे नया, कहीं भी चल रहा हो जहाँ आप चाहें।
  • CapSkip चल रहा हो और सुन रहा हो। Local mode जब Node-RED उसी Windows मशीन पर हो, Server mode जब न हो। दोनों का विवरण यहाँ मिलता है: कनेक्शन सेटिंग्स.
  • सुरक्षित form का पेज URL, और उसकी sitekey।
  • settings.js तक editor की पहुँच, अगर आप raw API के बजाय SDK वाला रास्ता चाहते हैं।

यहाँ कहीं browser की ज़रूरत नहीं है। Node-RED, Chrome को नहीं चला रहा, वह HTTP calls कर रहा है, इसलिए flow पेज के HTML से sitekey पढ़ता है और token को एक साधारण form field के रूप में वापस post कर देता है।

किसी flow से सॉल्वर को कॉल करने के दो तरीके

wiring शुरू करने से पहले एक चुन लीजिए, क्योंकि दोनों बहुत अलग flows बनाते हैं।

कौन सा रास्ताइसमें क्या लगता हैयह कब सही रहता है
raw API पर http request nodesएक submit node, एक delay, एक poll node और loop के लिए एक switchआप settings.js संपादित नहीं कर सकते, या आप चाहते हैं कि flow canvas पर पढ़ने लायक रहे
function node के अंदर Node SDKsettings.js की एक लाइन और Setup tab पर एक moduleआप चाहते हैं कि polling, backoff और timeouts आपके लिए संभाल लिए जाएँ

दूसरा रास्ता छोटा है और उसकी वजह जानने लायक है। raw API कहता है कि पंद्रह सेकंड रुकिए और फिर हर पाँच सेकंड पर poll कीजिए, और हाथ से बनाया गया flow इसे अक्षरशः मानता है। SDK इसके बजाय 250ms पर poll करना शुरू करता है और धीरे धीरे एक ऊपरी सीमा तक पहुँचता है, इसलिए वह आमतौर पर किसी delay node से काफ़ी पहले token लौटा देता है।

रास्ता एक: http request nodes और raw API

API 2captcha compatible है, यानी दो endpoints। आप in.php पर submit करते हैं और बदले में एक id मिलती है, फिर उसी id के साथ res.php को तब तक poll करते हैं जब तक वह यह कहना बंद न कर दे कि जवाब तैयार नहीं है। चार nodes, एक loop में जुड़े हुए।

flow में nodeसेटिंग
वह http request node जो submit करता हैhttp://127.0.0.1:8080/in.php पर POST, Return को parsed JSON object पर सेट
एक function node जो id रखता हैmsg.payload.request को msg.captchaId के रूप में सहेजें
एक delay nodeफिक्स्ड delay, reCAPTCHA v2 के लिए 15 सेकंड
वह http request node जो poll करता हैhttp://127.0.0.1:8080/res.php पर GET, Return को parsed JSON object पर सेट
एक switch nodeजब तक जवाब CAPCHA_NOT_READY रहे, वापस delay पर loop करें

submit node अपना body msg.payload से लेता है, इसलिए उसे उससे पहले वाले किसी function node में बनाइए। json को 1 करने से ही जवाब पुराने pipe-delimited text के बजाय JSON में आते हैं, जिससे आपका एक string split बच जाता है।

// Feed this into the submit node. No npm module needed.
msg.url = "http://127.0.0.1:8080/in.php";
msg.method = "POST";
msg.payload = {
    key: env.get("CAPSKIP_KEY") || "capskip",
    method: "userrecaptcha",
    googlekey: "YOUR_SITEKEY",
    pageurl: "https://example.com/page-with-recaptcha",
    json: 1
};
return msg;

poll node को वह id query string पर चाहिए। URL को किसी function node में बना लीजिए ताकि http request node के पास template करने को कुछ न बचे।

// After the delay. Loop back here until the answer arrives.
const key = env.get("CAPSKIP_KEY") || "capskip";
msg.url = "http://127.0.0.1:8080/res.php?key=" + key +
          "&action=get&id=" + msg.captchaId + "&json=1";
msg.method = "GET";
return msg;

जवाब के बारे में दो बातें। status 0 और request में CAPCHA_NOT_READY कोई error नहीं है, इसका मतलब जवाब अभी बन ही रहा है, और यही वह branch है जिसे आपका switch node वापस delay की ओर भेजता है। status 1 का मतलब है कि token msg.payload.request में है। loop को passes की एक समझदार संख्या पर सीमित कर दीजिए ताकि सचमुच न हल होने वाली कोई challenge हमेशा घूमती न रहे। polling की इस स्थिति को इस गाइड में और विस्तार से बताया गया है: CAPCHA_NOT_READY वाला जवाब, और हर parameter की सूची यहाँ है: CapSkip API डॉक्यूमेंटेशन.

रास्ता दो: function node के अंदर SDK

function node एक ऐसे sandbox में चलता है जिसके पास डिफ़ॉल्ट रूप से npm packages की पहुँच नहीं होती। दो settings इसे नियंत्रित करती हैं, और दोनों का व्यवहार अलग है।

पुराना विकल्प functionGlobalContext है, जिसमें आप module को settings.js में require करते हैं और node के अंदर global.get call से उसे वापस पढ़ते हैं। यह काम करता है, लेकिन instance का हर function node उसे देख लेता है, और कोई module जोड़ने का मतलब है Node-RED को दोबारा शुरू करना।

बेहतर विकल्प functionExternalModules है। इसे settings.js में true कर दीजिए और function node में एक Setup tab आ जाता है, जहाँ आप module का नाम देते हैं और वह variable भी जिसके नीचे वह दिखना चाहिए। deploy पर Node-RED उसे आपकी user directory में इंस्टॉल कर देता है, और सिर्फ़ वही node उसे देखता है।

// settings.js, in your Node-RED user directory.
module.exports = {
    // Lets a function node declare its own npm modules
    // on the Setup tab, installed on deploy.
    functionExternalModules: true,

    // The older, instance-wide alternative.
    // functionGlobalContext: { capskip: require("capskip") },
}

Node-RED को दोबारा शुरू कीजिए, कोई function node खोलिए, Setup tab पर जाइए, और variable नाम capskip के नीचे module capskip जोड़ दीजिए। एक बार deploy कीजिए और वह इंस्टॉल हो जाता है। उसके बाद node body उसे सीधे इस्तेमाल कर सकती है।

चरण 1: function node के अंदर हल करें

हल करना एक network call है जिसमें सेकंड लगते हैं, इसलिए node को asynchronously ख़त्म होना पड़ता है। मतलब message को सीधे return नहीं करना है। Node-RED का नियम यहाँ साफ़ है: काम किसी async block में कीजिए, message को node.send call से बाहर भेजिए, और node body से null return कीजिए ताकि कुछ भी दो बार न निकले।

// npm install capskip - or add it on the Setup tab
const solver = new capskip.CapSkip({
    host: "127.0.0.1",
    port: 8080,
    apiKey: env.get("CAPSKIP_KEY") || "capskip"
});

(async () => {
    try {
        const result = await solver.recaptcha(msg.sitekey, msg.pageUrl);
        msg.token = result.code;    // inject this into the form
        node.send(msg);
    } catch (err) {
        node.error(err, msg);       // routes to a catch node
    }
    node.done();
})();

return null;

node.error को दूसरे argument के रूप में msg देने से ही कोई catch node उस विफलता को पकड़ पाता है। इसे छोड़ दीजिए तो error debug sidebar में जा गिरती है और flow बस रुक जाता है, और यही सबसे आम वजह है कि Node-RED की कैप्चा branch ऐसी लगती है जैसे उसने कुछ किया ही न हो।

एक ही method reCAPTCHA v2, Invisible, Enterprise और v3 को कवर करता है। ये variants अलग calls नहीं बल्कि options हैं, इसलिए invisible widget वही एक लाइन है, बस options object में invisible को 1 कर दीजिए, और v3 का मतलब है version को v3 करना और साथ में एक action देना। Turnstile और GeeTest के अपने methods हैं, आकार वही है, और इन सबकी सूची यहाँ है: CAPTCHA solving SDK पेज.

चरण 2: पूरा flow एक ही node में

पेज fetch कीजिए, HTML से sitekey निकालिए, हल कीजिए, फिर बाक़ी form के साथ token वापस post कर दीजिए। अगर आप चाहते हैं कि flow सिर्फ़ एक inject node, यही function node और एक debug node हो, तो यही वाला संस्करण चिपकाइए।

// Module on the Setup tab: capskip. fetch is built in
// from Node 18, which Node-RED 3 and 4 both require.
const PAGE = "https://example.com/page-with-recaptcha";
const solver = new capskip.CapSkip({ host: "127.0.0.1", port: 8080 });

(async () => {
    try {
        const html = await (await fetch(PAGE)).text();
        const found = html.match(/data-sitekey=["']([^"']+)/);
        if (!found) { throw new Error("No data-sitekey on the page."); }

        // Solve, then submit straight away. Tokens go stale.
        const result = await solver.recaptcha(found[1], PAGE);
        const reply = await fetch(PAGE, {
            method: "POST",
            body: new URLSearchParams({
                "g-recaptcha-response": result.code
            })
        });

        msg.payload = { status: reply.status, token: result.code };
        node.send(msg);
    } catch (err) {
        node.error(err, msg);
    }
    node.done();
})();

return null;

हल उसी step में कीजिए जो submit से ठीक पहले है, किसी पहले वाली branch में कभी नहीं जो फिर किसी और चीज़ का इंतज़ार करती हो। reCAPTCHA token लगभग दो मिनट तक वैध रहता है और एक ही बार स्वीकार होता है, इसलिए जो flow पहले हल करता है, फिर किसी delay node में बैठा रहता है, फिर submit करता है, उसे ऐसी अस्वीकृति मिलेगी जो देखने में सॉल्वर की समस्या जैसी लगती ही नहीं। इस failure mode के बारे में इस गाइड में पढ़ना फ़ायदेमंद है: reCAPTCHA token की समय समाप्ति.

Node-RED और सॉल्वर को अलग अलग मशीनों पर चलाना

यह बात Node-RED में ज़्यादातर tools के मुक़ाबले और भी मायने रखती है, क्योंकि बहुत सारे installs किसी Raspberry Pi, NAS या छोटे Linux box पर होते हैं, और CapSkip एक Windows application है। अगर आपका setup ऐसा ही है, तो 127.0.0.1 का मतलब वही Pi है, सॉल्वर उस पर है नहीं, और call API तक पहुँचने से पहले ही connection refused के साथ fail हो जाती है।

इसका जवाब Server mode है और यह settings का बदलाव है, कोई अलग product नहीं। Local mode 127.0.0.1 से bind होता है और सिर्फ़ उसी डिवाइस को जवाब देता है। Server mode आपके network या public IP से bind होता है, इसलिए किसी Pi, container host या hosted Node-RED instance पर चलने वाला flow उसी API के ज़रिए Windows मशीन को कॉल करता है। एक static public IP उस पते को स्थिर रखता है। दोनों ही हाल में यह अब भी आपका हार्डवेयर है और अब भी बिना मीटर, इसलिए किसी व्यस्त flow की लागत किसी शांत flow से ज़्यादा नहीं होती।

// Same call, same SDK. Only the host moves.
const solver = new capskip.CapSkip({
    host: "10.0.0.12",
    port: 8080,
    apiKey: env.get("CAPSKIP_KEY")
});

जैसे ही सॉल्वर किसी network address पर सुनने लगे, key validation चालू कर दें, और हर Node-RED instance को उसकी अपनी key दें ताकि किसी एक को बाक़ियों को छुए बिना रद्द किया जा सके। key को node body के बजाय किसी environment variable में रखें: flows फ़ाइल disk पर JSON होती है और अक्सर किसी git repository में पहुँच जाती है। दोनों modes को यहाँ विस्तार से समझाया गया है: CapSkip सेटअप गाइड.

आम errors और उनका मतलब

आप जो देखते हैंकारणफिक्स
capskip is not definedmodule को Setup tab पर कभी घोषित ही नहीं किया गयाfunctionExternalModules को true कीजिए, फिर उसे जोड़कर deploy कीजिए
function node कुछ भी नहीं भेजताmessage को async block से भेजने के बजाय return कर दिया गयाnode.send कॉल कीजिए और node body से null return कीजिए
flow बिना किसी दिखने वाली error के रुक जाता हैnode.error को message argument के बिना कॉल किया गयादूसरे argument के रूप में msg दीजिए और एक catch node जोड़िए
connect ECONNREFUSED 127.0.0.1:8080Node-RED उस मशीन पर नहीं है जिस पर सॉल्वर चल रहा हैसॉल्वर को Server mode पर ले जाइए और host को उसके पते पर सेट कीजिए
poll वाला loop कभी ख़त्म नहीं होताswitch node पर प्रयासों की कोई सीमा नहीं हैpasses को किसी context variable में गिनिए और एक सीमा के बाद छोड़ दीजिए
form ऐसे token को ठुकरा देता है जो ठीक लगता हैहल कई nodes पहले हो चुका थाहल submit से ठीक पहले कीजिए, किसी पहले वाली branch में नहीं
ERROR_GOOGLEKEYsitekey उस page URL का है ही नहींजिस पेज पर आप submit कर रहे हैं, उसी से data-sitekey दोबारा पढ़िए

FAQ

क्या मुझे SDK चाहिए, या http request nodes से काम चल जाएगा?

दोनों काम करते हैं। http request वाले रास्ते में settings.js की पहुँच नहीं चाहिए और हर step canvas पर दिखता रहता है, जो कुछ teams को auditing के लिए पसंद आता है। SDK वाला रास्ता polling, backoff और timeouts आपके लिए संभालता है, और आमतौर पर token जल्दी लौटाता है क्योंकि वह पंद्रह सेकंड के बाद नहीं, एक चौथाई सेकंड के बाद ही जाँचना शुरू कर देता है।

क्या कोई hosted Node-RED instance मेरी मेज़ पर रखे सॉल्वर तक पहुँच सकता है?

सिर्फ़ Server mode में। hosted instance किसी और के infrastructure पर चलता है, इसलिए वहाँ 127.0.0.1 का मतलब उनका container है, आपकी मशीन नहीं। सॉल्वर को किसी पहुँच योग्य पते से bind कीजिए, उसे ऐसे firewall नियम के पीछे रखिए जो सिर्फ़ उस platform के outbound पतों को अनुमति दे, और key validation चालू कीजिए। पूरा सेटअप connection settings वाले पेज पर बताया गया है।

एक ही flow को सॉल्वर पर बोझ डालने से कैसे रोकूँ?

solve वाले node से पहले एक delay node को rate limit mode में लगा दीजिए। वह messages को queue में रखता है और एक तय दर पर छोड़ता है, और जब तीन schedules एक ही मशीन की ओर इशारा कर रहे हों तो यही वह throttle है जो आपको चाहिए। बिना किसी सीमा के loop में हल करना ही वह आम तरीका है जिससे एक batch timeouts के ढेर में बदल जाता है।

क्या यह वही है जो n8n में किया जाता है?

सॉल्वर वाला हिस्सा एक जैसा है, flow वाला नहीं। n8n अपने Code node को एक बंद sandbox में चलाता है जहाँ npm installs नहीं होते, इसलिए वहाँ या तो HTTP nodes हैं या कुछ नहीं। Node-RED किसी अकेले function node के लिए भी ख़ुशी से package इंस्टॉल कर देता है, इसीलिए यहाँ SDK वाला रास्ता मौजूद है। n8n वाला संस्करण यहाँ लिखा गया है: n8n कैप्चा workflow गाइड.

संक्षेप में

functionExternalModules चालू कीजिए, Setup tab पर capskip जोड़िए, और हल का काम एक ऐसे async block में कीजिए जो node.send call पर ख़त्म होता है और null return करता है। एक catch node जोड़िए और message को node.error तक भेजिए ताकि विफलताएँ दिखें। अगर Node-RED किसी Pi पर रहता है और सॉल्वर Windows पर, तो यह Server mode का मामला है और सिर्फ़ एक बदली हुई host string का। बाक़ी Node.js surface यहाँ है: Node.js कैप्चा सॉल्वर पेज, और reCAPTCHA के options यहाँ हैं: reCAPTCHA v2 सॉल्वर पेज.

उस flow को हर पाँच मिनट के schedule पर लगाने से पहले एक आख़िरी बात जान लेना ठीक रहेगा। CapSkip एक लोकल captcha सॉल्वर है जो उस हार्डवेयर पर चलता है जो पहले से आपका है, इसलिए हर पाँच मिनट पर हमेशा चलने वाले flow की लागत ठीक उतनी ही है जितनी उस flow की जिसे आप हाथ से चलाते हैं।