Google Chrome एक्सटेंशन: कुकीज़ और HTTP अनुरोध

Google Chrome एक्सटेंशन के विकास पर प्रकाशनों की एक श्रृंखला जारी है। सच है, यह इस पोस्ट के साथ समाप्त होता है, क्योंकि फिलहाल मेरे पास इस बारे में बताने के लिए अधिक कुछ नहीं है। आगे क्या होगा - हम देखेंगे।
इस विषय में, मैं कुकीज़ के साथ काम करने और HTTP अनुरोधों के निम्न-स्तरीय प्रसंस्करण के उदाहरण पर स्ट्रीट मैजिक कास्टिंग के बारे में बात करूंगा। इस पोस्ट की सामग्री पूरी तरह से मेरे पहले विस्तार पर आधारित है, जिसने बाद में अच्छी कार्यक्षमता हासिल कर ली।

कुकीज़


चलो कुकीज़ के साथ शुरू करते हैं। उनके साथ पूरी तरह से काम करने के लिए, मेनिफेस्ट में निम्नलिखित पंक्ति पर्याप्त है:
{ ... "permissions": [ "cookies", ... ], ... } 

एक्सटेंशन में सभी कुकीज़ तक पूर्ण पहुंच है। यहां तक ​​कि वे जो अस्थायी रूप से गुप्त विंडो में स्थापित किए गए हैं, अगर ब्राउज़र एक्सटेंशन कंट्रोल विंडो में पहुंच के लिए संबंधित चेकमार्क है। मैं ध्यान देता हूं कि एपीआई मेरे लिए असुविधाजनक लग रहा था। लेकिन आप यह पता लगा सकते हैं, और सब कुछ ठीक काम करता है।
इसके आधार पर, साइटों पर विभिन्न सत्रों के बीच भंडारण और स्विचन के लिए एक विस्तार विकसित किया गया था। प्रारंभ में, लक्ष्य और विचार सामाजिक खेलों में बहु-खेती की सुविधा के लिए था, लेकिन फिर मैंने इसे एक सार्वभौमिक उपकरण के रूप में तैनात किया।

यह कैसे काम करता है?
ब्राउज़र एपीआई में तरीके बना रहे हैं: chrome.cookies.get(details, callback) एक कुकी के बारे में डेटा प्राप्त करने के लिए, सभी कुकीज़ के बारे में डेटा प्राप्त करने के लिए समान getAll विधि (समान मापदंडों के साथ, लेकिन विवरण एक फिल्टर की तरह काम करता है, यह बहुत सुविधाजनक निकला) , और chrome.cookies.set(details, callback) । मैं लोकप्रिय रूप से मापदंडों और उपयोग का वर्णन नहीं करूंगा, यह प्रलेखन में पाया जा सकता है। बेहतर है कि सीधे मुद्दे पर जाएं।
बुनियादी तरीके:
 function deleteCookies() { //  cookies   for (var i = 0; i < .length; i++) { try { var d = [i]; var u = ((d.secure) ? "https://" : "http://") + d.domain + d.path; chrome.cookies.remove({ url: u, name: d.name, storeId: d.storeId }); } catch (e) { console.error("Error catched deleting cookie:\n" + e.description); } } } function setCookies(c) { // cookies   for (var i = 0; i < c.length; i++) { try { var d = c[i]; var b = { url: ((d.secure) ? "https://" : "http://") + d.domain, name: d.name, storeId: d.storeId, value: d.value, path: = d.path, secure: = d.secure, httpOnly: = d.httpOnly, }; if (!d.hostOnly) { b.domain = d.domain; } if (!d.session) { b.expirationDate = d.expirationDate; } chrome.cookies.set(b); } catch (e) { console.error("Error setting cookie:\n" + e.description) } } } 

बस storeId के बारे में स्पष्ट करना चाहते हैं। ब्राउज़र में कुकीज़ ऐसे कंटेनरों में संग्रहीत की जाती हैं। यहां तक ​​कि एक chrome.cookies.getAllCookieStores(callback) विधि भी है, जिसके जवाब में कुछ इस तरह से लौटाया जाता है:
 [{ id: 0, tabIds: [1,2,3,4], },] 
लेकिन हमेशा 1 या 2 ऑब्जेक्ट वापस किए जाते हैं: एक सामान्य, और गुप्त विंडो के लिए एक (यदि यह खुला है, और इस विंडो तक विस्तार की पहुंच है)। टैबआईड्स पैरामीटर की उपस्थिति को देखते हुए, यह या तो योजनाबद्ध और भूल गया था, या इन स्टोरों को प्रबंधित करने और विशिष्ट स्टोरों के टैब को बांधने की क्षमता अभी भी योजनाबद्ध है। यदि यह पहले से ही काम करता है, तो यह विचार को लागू करने में मदद करेगा, जिसकी चर्चा अगले भाग में की जाएगी।

तो, बुनियादी तरीके हैं, आप स्विचिंग प्रोफाइल कर सकते हैं। नीचे फेसबुक के उदाहरण के लिए कोड है।
 var profiles = JSON.parse(localStorage.profiles); //    var inuse = localStorage.inuse; //  var cookies = ['facebook.com','secure.facebook.com','on.fb.me']; //,     cookies function newProfile(){ //      cookies var ii = 0; // cookies   callback,       ,    var initer = function(cii){ chrome.cookies.getAll({domain:cookies[cii]}, function (f){ var nc = profiles.length-1; profiles[nc].cookies = profiles[nc].cookies.concat(f); if (cii<(cookies.length-1)){ cii++; initer(cii); } else{ saveSettings(); //... } }); } chrome.cookies.getAll({domain:cookies[0]}, function (f){ var nc = profiles.length; profiles[nc] = {title:'New profile '+nc,cookies:f}; inuse = nc; if (ii<(cookies.length-1)){ ii++; initer(ii); } else{ saveSettings(); //... } }); } function switchProfile(d) { //  if (profiles[d] != undefined && profiles[d] != null && d != inuse) { //cookies, ,  .        cookies //     var deleter = function(cii){ chrome.cookies.getAll({domain:cookies[cii]}, function (f){ deleteCookies(f); if (cii < (cookies.length-1)){ cii++; deleter(cii); } else{ restoreCookies(profiles[d].cookies); inuse = d; saveSettings(); //...+ } }); } deleter(0); } } 

उपरोक्त कोड प्रदर्शन के लिए थोड़ा सरल है। वास्तव में, विस्तार कई साइटों का समर्थन करता है, इसलिए प्रसंस्करण कार्यों का उपयुक्त रूप है। मेरे स्वयं के कार्य, मुझे लगता है, समझाने का कोई मतलब नहीं है, टिप्पणियों से सब कुछ स्पष्ट है।
ब्राउज़र में संग्रहीत कुकीज़ में परिवर्तन के लिए विस्तार किसी भी तरह से प्रतिक्रिया नहीं करता है, यह केवल उस समय की स्थिति को संग्रहीत करता है जब प्रोफ़ाइल बनाई गई थी। लेकिन एपीआई में इसी तरह की घटनाएं हैं जिन्हें आप सदस्यता ले सकते हैं और किसी तरह उन्हें संभाल सकते हैं। यह भी ध्यान दें कि यदि साइट पर सुरक्षा है या यदि पिछले सभी सत्रों को बंद करना संभव है, तो ये कुकीज़ आईपी पते को बदलने या सत्र हटाए जाने के कुछ समय बाद काम करना बंद कर सकती हैं। लेकिन कई सेवाओं और सामाजिक नेटवर्क के लिए, स्थायी प्राधिकरण के बिंदु पर, सब कुछ अनिश्चित रूप से काम करता है।
लगभग इस रूप में, मेरा समाधान आज तक काम करता है। और लंबे समय तक जोड़ने के लिए कुछ भी नहीं था, अगर एक घटना के लिए नहीं।

HTTP अनुरोध


ऐसा हुआ कि एक संसाधन तक पहुंच मालिक द्वारा प्रतिबंधित थी। इसके अलावा, Referer हैडर के अनुसार फ़िल्टरिंग हुई। समाधान की तलाश में, मैंने वेबरेंस एपीआई के कार्यों के बारे में सीखा। वे आपको ब्राउज़र में होने वाले सभी अनुरोधों को देखने और प्रबंधित करने की अनुमति देते हैं।
चलिए शुरुआत करते हैं।
 { ... "permissions": [ "webRequest", "webRequestBlocking" ], ... } 

पहला पैरामीटर घटनाओं को अनुरोध करने के लिए हैंडलर जोड़ने की क्षमता प्रदान करता है, दूसरा, इसके अलावा, आपको उन्हें संशोधित करने या ब्लॉक करने की भी अनुमति देता है।
विस्तार
एपीआई विवरण में अब घोषणात्मक सूचना शामिल है। विवरणों को देखते हुए, यह समान कार्यक्षमता प्रदान करता है, लेकिन बहुत तेज़ होना चाहिए, क्योंकि नियमों को सीधे ब्राउज़र में निष्पादित किया जाता है, और जावास्क्रिप्ट में नहीं। लेकिन अभी (और लंबे समय के लिए) यह बीटा स्टेज में है।
गति के लिए, मेरा एक्सटेंशन खोजता है और यदि आवश्यक हो, तो कुछ चर को संशोधित करता है और हेडर का अनुरोध करता है, और सभी अनुरोधों को पकड़ता है। मैंने इस से ध्यान देने योग्य ब्रेक नहीं देखा।
प्रकाशन के संबंध में
जिस एक्सटेंशन में मैंने पहली बार इस एपीआई का उपयोग किया था, वह शुरू में इसके बिना काम करता था। पहले अपडेट के बाद, जहां मैंने इन सुविधाओं को चालू किया, उन्हें मैनुअल मॉडरेशन के लिए भेजा गया, जिसमें लगभग दो सप्ताह लगे। कोई समस्या नहीं होने के बाद, एक और विस्तार के समान कार्यक्षमता के साथ भी, उत्पन्न नहीं हुई। इसलिए, मुझे यकीन नहीं है कि अब ऐसे उपाय किए जा रहे हैं।

एपीआई एक HTTP अनुरोध के जीवन चक्र से प्रत्येक घटना के लिए हैंडलर को असाइन करने की क्षमता प्रदान करता है और अनुरोध के साथ लगभग किसी भी कार्रवाई को करता है। अन्य जानकारी के बीच, क्या महत्वपूर्ण है, अनुरोध आरंभकर्ता को मापदंडों में भी पारित किया गया है: टैब, पृष्ठ आदि की आईडी। इसके आधार पर, विचार का जन्म विभिन्न टैब में एक साथ कई प्रोफाइलों को रखने के लिए संभव बनाने के लिए हुआ था। यह पर्याप्त है, सब के बाद, प्रोफ़ाइल से आवश्यक लोगों के साथ भेजे गए कुकीज़ को बदलने के लिए प्रत्येक अनुरोध में।
जल्दी से नहीं कहा!
OnBeforeSendHeaders ईवेंट के लिए उपयुक्त श्रोता असाइन करें और हेडर को आवश्यक लोगों के साथ बदलें।
 var tabs = {}; //       function openProfile(id,url){ //  if (url.indexOf('#')>-1) url = url.substr(0,url.indexOf('#')+1) + encodeURIComponent(url.substr(url.indexOf('#')+1)); // , -          ,    loadSettings(); chrome.tabs.create({url:url},function(r){ //         if (r) tabs[r.id] = new Array(tinuse,id,profiles[id].cookies.slice()); }); } chrome.webRequest.onBeforeSendHeaders.addListener(function(d){ if (d.tabId){ //   td = d.tabId; if (tabs[td]){ //     td = tabs[td]; for (var i = 0; i < d.requestHeaders.length; i++){ if (d.requestHeaders[i].name=='Cookie'){ var cks = d.requestHeaders[i].value.split('; '); // Cookies    for (var j = 0; j < cks.length; j++){ cks[j] = cks[j].split('='); for (var k = 0; k < td[2].length; k++){ if (td[2][k].name==cks[j][0]){ // cks[j][1] = td[2][k].value; break; } } cks[j] = cks[j].join('='); } d.requestHeaders[i].value = cks.join('; '); //  cookies } } } } return {requestHeaders: d.requestHeaders}; //    },{ urls: ["<all_urls>"] //        .    ,         },[ "blocking", //    "requestHeaders" //   ]); 

पहले तो ऐसा विकल्प निकला। जैसा कि यह निकला, यह पर्याप्त नहीं है। निष्क्रियता के कारण (प्रोफ़ाइल के अंतिम उपयोग के बाद कितना समय लग सकता है? इसके अलावा, कुकीज़ संग्रहीत हैं जो निर्माण के समय थे, और काम के दौरान अपडेट नहीं किए गए हैं।) सत्र समाप्त हो रहा है और प्राधिकरण पृष्ठ पर पुनर्निर्देशन तब होता है, जहां, फिर भी, प्राधिकरण। स्वचालित रूप से होता है, लेकिन एक नया सत्र बनाया जाता है। इसलिए, इसे संसाधित किया जाना चाहिए।
 chrome.webRequest.onHeadersReceived.addListener(function(d){ if (d.tabId){ td = d.tabId; if (tabs[td]){ td = tabs[td]; //Cookies      : //name: "Set-Cookie" //value: "cookiename=value; expires=Sun, 22-Dec-2013 03:31:23 GMT; path=/; domain=.domain.com" for (var i = 0; i < d.responseHeaders.length; i++){ if (d.responseHeaders[i].name=='Set-Cookie'){ var sk = d.responseHeaders[i].value.split('; '); sk[0] = sk[0].split('='); var ck = {name:sk[0][0],value:sk[0][1]}; for (var j = 1; j < sk.length; j++){ sk[j] = sk[j].split('='); ck[sk[j][0]] = sk[j][1]; } for (var k = 0; k < td[2].length; k++){ if (td[2][k].name==ck.name && td[2][k].path==ck.path && td[2][k].domain==ck.domain){ //   cookie,   td[2][k].value = ck.value; break; } } //    ,      cookies   ,          d.responseHeaders.splice(i,1); i--; } } } } return {responseHeaders: d.responseHeaders}; },{ urls: ["<all_urls>"] },[ "blocking", "responseHeaders" ]); 

अब सब कुछ काम करता है। प्रारंभ में, मैंने संग्रहीत प्रोफ़ाइल डेटा में कुकीज़ को अपडेट करने के बारे में सोचा था, लेकिन फिर यह गड़बड़ हो जाएगा। आप इसे एक नए टैब में खोल सकते हैं, और फिर एक अलग प्रोफ़ाइल के तहत लॉग इन कर सकते हैं, कुछ और कर सकते हैं, और सब कुछ खो जाएगा। इसलिए, कार्य की अवधि के लिए एक अस्थायी प्रतिलिपि बनाने का निर्णय लिया गया था। लेकिन अगर ऐसा है, तो उसी डेटा को हटाना होगा। और वर्तमान से नए टैब खोलने से निपटने के लिए भी चोट नहीं करता है।
 chrome.tabs.onCreated.addListener(function(tab){ if (tab.openerTabId){ //       - -  if (tabs[tab.openerTabId]){ tabs[tab.id] = tabs[tab.openerTabId]; } } }); chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) { //   .  -    ID –  if (tabs[tabId]) delete tabs[tabId]; }); 

उसी तरह यह मेरे विस्तार में काम करता है।
विकास के दौरान, एक अधिक वैश्विक विचार भी सामने आया। शुरू में खाली कुकीज़ के साथ इन अलग-थलग टैब बनाने के लिए एक विस्तार लिखें और पहले से ही सभी घटनाओं को पूरी तरह से संभाल लें। इस तरह के निष्कर्ष, कार्यक्षमता में गुप्त विंडो के समान हैं। लेकिन मैंने अभी तक किसी भी तरह से बाकी टैब के बीच इस तरह के टैब को उजागर करने की क्षमता के ब्राउज़र में पूरी तरह से अनुपस्थिति के माध्यम से इससे निपटा नहीं है। फिक्सिंग कुछ नहीं है, विंडोज़ का उत्पादन भी बिंदु नहीं देखता है। इसलिए, यह अभी भी एक विचार के रूप में हवा में है।

ये "चमत्कार" ब्राउज़र द्वारा दिए गए टूल का उपयोग करके किए जा सकते हैं। उपयोग की गई सादगी और विकास साधनों को ध्यान में रखते हुए, मैं फ़ायरफ़ॉक्स की तुलना में क्रोम की प्रशंसा करना कभी नहीं भूलता।
वैसे, प्रस्तावित कार्यक्षमता के कार्यान्वयन से कुकीज़ को टैब बनाने और बाँधने की क्षमता से बहुत मदद मिलेगी, जिसके बारे में मैंने ऊपर लिखा था। मैं वास्तव में आशा करता हूं कि किसी दिन यह होगा, साथ ही साथ टैब को भेद करने की क्षमता भी होगी। उदाहरण के लिए, उन्हें रंग के साथ हाइलाइट करें, जैसा कि IE में किया गया है।
खैर, आखिरकार। विज्ञापन के लिए मत गिनो। अगर किसी को दिलचस्पी है, तो मैंने इस पोस्ट में जो विस्तार बताया है वह "वीके + स्विचर" है। मैंने स्रोतों को कहीं भी प्रकाशित नहीं किया है, लेकिन यदि आप गहराई से खुदाई करना चाहते हैं, तो आप एक्सटेंशन के साथ ब्राउज़र फ़ोल्डर में संरचना को स्थापित और देख सकते हैं।

Source: https://habr.com/ru/post/In171959/


All Articles