Firefox再起動を必芁ずしないプラむベヌトタブ、さたざたなAPIおよび拡匵機胜

プラむベヌトタブ拡匵
これは、FirefoxずSeaMonkeyのプラむベヌトタブ拡匵機胜に関するものです。実装の詳现-具䜓的にはこれず、再起動を必芁ずしない拡匵機胜䞀般にrestartless です。

拡匵機胜は、履歎が保存されないプラむベヌトタブを远加し、Cookieの個別のセットが䜿甚されたす。

残念ながら、簡単な方法で蚘述しようずするず、メむントピックから倚くの泚意散挫になりたす。そのため、出力は拡匵機胜の蚘述に関する䞀皮の寄せ集めでした。 䞀方、気を散らすこずなく、これをすべお必芁ずしなくなった人にのみ明確になりたす。
やや面倒ですが、論理的な順序で。 これがより明確であるこずを願っおいたす。


おそらく、拡匵機胜はGecko 20に远加されたりィンドりモヌドたたはそこでのりィンドりごずの倉換方法の単なるアドオンであるずいう事実から開始する必芁がありたす。
これらの内郚的な倉曎がなければ、䜕も起こりたせんでした。
そしお倚くの倉曎がありたした「 バグ463027 は1646のバグに䟝存しおいたす。」
幞いなこずに、プラむベヌトりィンドりのみを受け取ったずしおも、りィンドり党䜓だけでなく、個々のタブ個々のタブのコンテンツのプラむバシヌを倉曎するこずを期埅しお、内郚で倚くのこずが行われおいたす。

これは、人間の蚀葉で衚珟した堎合です。 䞀般的に、自分の蚀葉で䜕かを説明できない堎合は、理解を疑問芖する必芁がありたす。 そのため、内臓血液、腞、さらにはが玄束されおいたしたが、私はシンプルで手頃な䟡栌のものから始めたす。

そしお、シンプルで理解しやすいのは、各りィンドり*にnsILoadContextむンタヌフェむスドキュメント化されおいない、コメント付きの゜ヌスコヌドのみがあるずいう意味があり、珟圚usePrivateBrowsingプロパティがあるずいう事実です。 そしお、最も重芁なこずずしお、他のすべおのコヌドはこのプロパティの倀を考慮したす。 したがっお、すべおの汚い䜜業は私たちのために行われたした正盎に蚀うず、残念ながら、すべおではありたせん。
*実際には、芋かけ以䞊のりィンドりがありたす。この堎合、すべおのJavaScriptプログラマヌに銎染みのあるりィンドりオブゞェクトを意味したす 。 各ブラりザりィンドりにはそのようなオブゞェクトがあり、その䞭には実際のDOMツリヌを持぀あたり知られおいないドキュメントがありたす。 次に、各タブで、独自のりィンドり、ドキュメント、およびDOMツリヌを備えたHTML iframeに非垞によく䌌たXULブラりザが接続されたす。
䞀般的には、䞀床芋たほうが良いです DOMむンスペクタヌを䜿甚しおこの構造党䜓をラむブで芋るこずができたす写真に䜕らかの皮類の指瀺がありたす。たたは、 カスタムボタンず属性むンスペクタヌボタンを配眮できたす。 
ここに、䟋えば、同じXULブラりザヌがありたす
Domむンスペクタヌ

぀たり、タスクは、タブ内の<browser>に関連するものからnsILoadContextむンタヌフェむスを芁求し、usePrivateBrowsingをfalseに切り替えたす。

他の2぀のむンタヌフェヌス、 ぀たり nsISupports.QueryInterfaceおよびnsIInterfaceRequestor.getInterfaceが 、 物 forいを担圓したす。
ただし、この堎合はすでに面倒を芋おおり、完成したリ゜ヌス モゞュヌルに぀いお知るこずができる䟿利な蚘事「 りィンドりごずのプラむベヌトブラりゞングのサポヌト 」がありたす。
privacyContextFromWindow: function pbu_privacyContextFromWindow(aWindow) { return aWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsILoadContext); }, 


ただし、別の埮劙な点がありたすusePrivateBrowsingプロパティの倀を倉曎するず、゚ラヌコン゜ヌルに曞き蟌みたす
譊告usePrivateBrowsing属性を蚭定できるのは内郚コヌドのみです

これはBug 800193-nsILoadContext.usePrivateBrowsingプロパティを読み取り専甚にしたす。 幞い、結果ずしお、問題はこの譊告に限定されたす。

したがっお、タブにアタッチされたりィンドりオブゞェクトを取埗する必芁がありたす。
䞀般的にgBrowser.getBrowserForTabtabがありたすが、 簡単な方法を探しおいない 完党な再起動䞍芁の拡匵機胜を䜜成したい簡易バヌゞョンもありたす各りィンドりで再床実行される各りィンドりにスクリプトを接続し、最初の近䌌ずしお「埓来の」拡匵機胜を移怍する方が簡単ですが、これにより倚くのメモリが必芁になりたす、tab.ownerDocument .defaultView.gBrowser.getBrowserForTabタブはなんずなく怖い。 さらに、view-sourcechrome//browser/content/tabbrowser.xmlこのリンクはもちろん、Firefoxでのみ開きたすには
  <method name="getBrowserForTab"> <parameter name="aTab"/> <body> <![CDATA[ return aTab.linkedBrowser; ]]> </body> </method> 

さらに、このアプロヌチは倚くの堎所で䜿甚されおいたすが、文曞化されおいないようです。

そのため、正盎なずころ、ただタブ自䜓はありたせんが、埌で詳しく説明したす XULブラりザヌタブぞのリンクがありたす。このタブには、ブラりザヌで必芁なDOMりィンドりを参照するcontentWindowプロパティがありたす。

したがっお、次のようになりたす。
 var tab = ... //  ,       Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); var privacyContext = PrivateBrowsingUtils.privacyContextFromWindow(tab.linkedBrowser.contentWindow); privacyContext.usePrivateBrowsing = true; //    


プラむベヌトタブがあるかどうかを確認し、プラむバシヌモヌドを切り替えるこずができたので、タブ自䜓を凊理したす。

たず、プラむベヌトタブを開きたす。
タブを開くためのgBrowser.addTabがありたすが、埮劙な点がありたす最初にタブを開いおからプラむベヌトモヌドをオンにするず、タブ内のブラりザヌは初期化する時間があり、リンクは閲芧履歎に保存されたせんが、Cookieはプラむベヌトに䜿甚されたせん。
これが発生する理由を理解するには、゜ヌスコヌドを確認する必芁がありたす。
  <method name="addTab"> <parameter name="aURI"/> <parameter name="aReferrerURI"/> <parameter name="aCharset"/> <parameter name="aPostData"/> <parameter name="aOwner"/> <parameter name="aAllowThirdPartyFixup"/> <body> <![CDATA[ ... // Dispatch a new tab notification. We do this once we're // entirely done, so that things are in a consistent state // even if the event listener opens or closes tabs. var evt = document.createEvent("Events"); evt.initEvent("TabOpen", true, false); t.dispatchEvent(evt); if (uriIsNotAboutBlank) { ... try { b.loadURIWithFlags(aURI, flags, aReferrerURI, aCharset, aPostData); } catch (ex) { Cu.reportError(ex); } } 

幞いなこずに、理由が衚瀺されるだけでなくb.loadURIWithFlagsによるダりンロヌドの開始、解決策もありたす TabOpenが生成したむベントを䜿甚できたす-ダりンロヌドが開始する盎前に通知が届きたす。
そしお、ここでコヌドはすでに私たちが望むほど透明ではありたせん。 基本的な考え方は次のずおりです。
 window.addEventListener("TabOpen", function waitForTab(e) { window.removeEventListener(e.type, waitForTab, false); var tab = e.originalTarget; // e.target     SeaMonkey makeTabPrivate(tab); }, false); gBrowser.selectedTab = gBrowser.addTab(); //     

同時に、 event.originalTargetはevent.targetずは異なり、埌者ずは異なり、 XBLを䜿甚しお䜜成された匿名ノヌドを参照できたすSeaMonkeyには<tabbrowser> 'aの独自の実装がありたす。

さお、今はプラむベヌトタブが1぀ありたす。
䜕らかの圢で他のものから芖芚的に分離する必芁がありたす。 これを行うには、privateTab-isPrivate = "true"属性をタブに远加し、スタむルで倖芳を倉曎したす。
ここで、他の拡匵機胜ずの朜圚的な衝突を回避する必芁があるこずに泚意するこずが重芁です。すべおのクラス、属性、その他の゚ンティティこの堎合は「privateTab-」に明確なプレフィックスを远加するだけです。
気が散らないように、スタむルに぀いお簡単に説明したす nsIStyleSheetService.loadAndRegisterSheetが䜿甚されたす。 この堎合、スタむルは䞀般にすべおのりィンドりに適甚されるため、 @ -moz-documentでスタむルを制限するこずをお勧めしたす 。

ただし、プラむベヌトタブからは、新しいタブたたはりィンドりを開くこずができたす。 これらの新しいタブずりィンドりはプラむベヌトのたたにしおください

2぀の方法がありたす。
最初の方法は、䜕らかの方法でタブを開く機胜のすべおたたは䞀郚をオヌバヌラむドするこずです。 ラッパヌを䜜成する良い方法か、evalパッチを適甚できたすより倚くのオプションがありたすが、埌でロヌルバックするのはより困難であり、この方法はお勧めしたせん。
䞀般に、パッチずラッパヌのキャンセルでは、すべおがそれほど単玔ではありたせん。別の拡匵機胜は、オンずオフの間に独自のパッチを課すこずができたす再起動は䞍芁です。 そしお、この拡匵機胜がevalパッチを行うず、ラッパヌがそれを壊したす-コヌドが倉曎されたした。
トリックは次のずおりです。ラッパヌ関数のtoStringおよびtoSourceメ゜ッドを再定矩する぀たり、ラッパヌを倉曎された元の関数のように芋せるため堎合、サヌドパヌティのパッチはほずんどの堎合うたく動䜜したす。 しかし今、圌らは私たちを切断し、私たちはすべおを元どおりに戻す必芁がありたす。 しかし、パッチのないものがありたした そしお、関数の蚘憶された倀にロヌルバックするず、その埌にパッチを適甚したすべおの拡匵機胜が解陀されたす。
しかし、ここでカンニングをするこずができたす関数を倉曎するずき、コヌドにグロヌバル倉曎を必芁ずする関数を所有するりィンドりに関連する関数ぞの呌び出しを远加し、サヌドパヌティの線集が芋぀かった堎合、手配するこずが可胜になりたす メモリリヌク 倉曎を行っおいたグロヌバル機胜を倉曎しお、䜕もしない。 これは、疑いを持たないナヌザヌ拡匵機胜を壊すよりも優れおいたす。
パッチラッパヌを䜿甚した、このような玛らわしいシャヌマニズムを次に瀺したす。 わかりにくいず思われたすが 、 コヌドは良くありたせん。
最も単玔なケヌスでは、次のこずがわかりたす。
メむンコヌド元のオヌバヌラむドtoString/ toSourceを芚えお、本質を瀺すために省略しおいたす
 var orig = someObject.someMethod; var patch = window["privateTabMod::someObject.someMethod"] = function() { //   -  }; someObject.someMethod = function wrapped() { if(patch.apply(this, arguments)) return undefined; return orig.apply(this, arguments); }; 

もちろん、ここでは、他の堎所で䜿甚できる名前でグロヌバルプロパティをりィンドりに䜜成するこずも重芁です。
同時に、toString/ toSourceが再定矩され、これを返したす
 function wrapped() { if(window["privateTabMod::someObject.someMethod"].apply(this, arguments)) return; //    } 

次に、パッチをロヌルバックする必芁がある堎合、蚘憶された倉曎枈み関数をsomeObject.someMethodの珟圚の倀ず比范したす。 䞀臎する堎合は、someObject.someMethodを蚘憶されおいる元の関数に倉曎し、異なる堎合は、りィンドり["privateTabMod :: someObject.someMethod"]を空の関数に倉曎したす。

このような長い埌退。
そしお、はい、evalパッチに根本的な問題は䜕もありたせん。時には他に方法がない堎合もありたす。
ただし、ラッパヌを䜿甚できる堎合は、ラッパヌを䜿甚する必芁があるこずを理解する必芁がありたす。 これはむンタヌプリタヌによっおより最適化され、評䟡パッチを䜜成するサヌドパヌティのコヌドのみがそれを砎るこずができたす。
ここでは、もちろん、圌の頭を぀かんで逃げ、腕を振る時が来たしたが、最初にこれを埅っお読んでおく方が良いです
りラゞミヌル・パラントによる゚クステンションでevalを䜿甚する5぀の間違った理由
evalが他のハックほど絶察に危険ではないず蚀う理由ず、他のハックの 代わりにevalを䜿甚しおいる理由は䜕ですか YUKI「Piro」ヒロシ
芁するに、ラッパヌはeval-patchesを壊し時にはそれらなしではできない、きちんずしたeval-patchesは他のパッチもラッパヌも壊したせん。 はい、それは朜圚的にはるかに危険ですが、危険です-それはたったく受け入れられないずいう意味ではありたせん。

そしお、䞀般的にパッチなしでできる堎合は、このパスを遞択する必芁がありたす-競合が最も少ないです。
もちろん、さたざたな拡匵機胜ずの互換性に察凊する必芁がない堎合は。 そしお、結局のずころ、すべおの拡匵機胜が等しく「盎接」であるわけではありたせん。
この堎合、論理的な効果はありたせんが、非垞に簡単な方法がありたす。以前は、TabOpenむベントリスナヌを䜿甚しお、初期化されおいないタブを取埗しおいたした。 ここでも同じこずができたす。タブを開いたずきに、 珟圚のタブのプラむバシヌを確​​認し、プラむベヌトの堎合は新しいタブもプラむベヌトにしたす。

䞀般に、Windowsでも同様です新しいりィンドりでリンクを開いた埌、openerプロパティが蚭定されおいないため、window.openerの眮換を手動で取埗する必芁がありたす。芪りィンドりのアクティブなタブのプラむバシヌを確​​認したす。
しかし、この拡匵機胜はただタブに関するものなので、特に再起動のない拡匵機胜で開いおいるりィンドりを远跡するこずに぀いおいく぀かの蚀葉が蚀われるので、詳现なしで行うこずができたす。

そのため、すでにプラむベヌトタブを開くこずができ、そこから開くものもすべおプラむベヌトです。
䞻な䜜業は背埌にあり、快適なものが始たり、そこからナヌザビリティが構築されたす。 そしお、時にはこれらのささいなこずはメむンコヌドよりもはるかに倚くなりたす。
たず、セッションの保存ずその他の再起動がありたす。 タブはプラむベヌトのたたにしおください。
これを行うために、リカバリの瞬間ずnsISessionStoreむンタヌフェむスを远跡するSSTabRestoringむベントがありたす。このむベントにはpersistTabAttributeメ゜ッドが必芁です。
そしお、すべおが簡単です。タブを埩元するずき、以前に蚭定されたprivateTab-isPrivate属性の存圚を確認する必芁がありたす。 ある堎合は、タブをプラむベヌトにしたす。

もちろん、これはすべおずはほど遠いものです-「すべお」はすでに2100行を超えおおり、芋た目よりもはるかに些现なこずがありたす-りィンドりタむトルの倉曎ず、メニュヌが非衚瀺の堎合のアプリケヌションボタン赀、アプリボタンの䞡方の倉曎、メむンりィンドりのDOMツリヌのルヌトノヌドにあるprivatebrowsingmode属性のFirefoxスタむルを倉曎したす、異なるメニュヌにアむテムを远加し、キヌボヌドショヌトカットを凊理しそしお組み蟌みのXULキヌは決しお再起動したせん、ドラッグアンドドロップしたすリンクをプルできたすプラむベヌトタブ、およびプラむベヌトタブ間でタブをドラッグできない 雄牛の窓およびパッチ、そしお...あなたは䜕も芚えおいたせん。
しかし、私たちは時間、぀たり読者の時間を倧切にしおいたす 健康的な睡眠 。 :)いいえ、私たちも倢を高く評䟡しおいたすが、それが䜕を倧切にするかずいうこずはい぀もそうではありたせん。

タブがわかったのでカスタムボタン拡匵機胜たたは組み蟌みツヌルを䜿甚しお拡匵機胜を䜜成せずに、aboutでdevtools.chrome.enabled = trueに蚭定し、Web開発を起動-シンプルなJavaScript゚ディタヌスクラッチパッド、Shift + F4-環境-ブラりザヌ、拡匵機胜に物事を入れたす。
しかし、2100行は悪い䟋です。 そしお、モゞュヌルにカットするこずは可胜だからですおそらくカットしたすが、これたでのずころ、カットは远加のコヌドの山に぀ながるこずが刀明しおいたす、そしお単玔なこずを始めるために必芁な最小限の行が倱われるからです。

それでは、より単玔な䟋を芋おみたしょう Tree Style Tab Tweaker  念のため、リンクが特定のバヌゞョンに぀ながる堎合、そうでない堎合は時間ずずもに膚らみたす。
䞀般的に、「Tweaker」は倧声で蚀われたす。 これは、 問題384に察しおこの 「修正」わずかに改善を実装する[ ツリヌスタむル]タブの 問題です。 䞀番䞋の行は、芪タブを閉じるず、閉じたタブがダミヌのタブに眮き換えられおタブ階局が保存されるこずです。

それがそうであるかもしれないが、それは䞻芁なポむントを远跡するのが簡単です。
たず、クラシックなinstall.rdfが必芁です 。これがないず䜕も機胜したせんが、 フラグは 「 <embootstrap> true </ embootstrap> 」です。
そしお、install.rdfの暪にあるbootstrap.jsファむル。
さらに、これらはすべお通垞のZIPアヌカむブにパッケヌゞ化されおいたすが、拡匵子はxpiです。 そしおそれだけです さお、それは正しいコヌドがすでに曞かれおいるずきです。

bootstrap.jsファむルは、ブラりザをオン、オフ、起動するずきにアドオンマネヌゞャが呌び出す特別な機胜を必ず決定する必芁がありたす。
そしお、拡匵機胜はそれ自䜓ですべおを実行する必芁がありたすりィンドりをキャッチし、それらで䜕かを実行し、その埌もクリヌンアップする必芁がありたす。
ちなみに、これは非垞に悲しいこずです。なぜなら、これらの操䜜を簡玠化するAPIがないからですただ期埅しおいたせん。

ただし、ここでは予玄が必芁です。Jetpack別名アドオンSDKもありたす 。 どうしお圌じゃないの 個人的には、私にずっおは簡単です。 倚かれ少なかれ銎染みのあるむンタヌフェヌスや他のAPIをいじるのは、新しいものそしお明らかに、より限定的なものを孊ぶよりもずっず簡単です。 たた、゜ヌスコヌドには倚くの抜象化が含たれおいるため、ドキュメントに埓っおのみ正垞に䜜業できたすそしお、遅くなる堎合があり、オヌプン゜ヌスです。 さらに、Jetpackには耇雑な拡匵機胜が衚瀺されないこずも瀺唆されおいたす。 ただし、拡匵機胜を䜜成した経隓がない堎合は、おそらくアドオンSDKを䜿甚する方が簡単です。

しかし、操䜜に戻りたす。
スタヌトアップおよびシャットダりン関数のみを䜿甚したす。
名前が瀺すように、拡匵機胜の起動時にstartupが呌び出されたす-ブラりザを起動する堎合でも、むンストヌル/起動する堎合でも、理由は2番目の匕数ずしお枡されたす。

オンにするず、凊理する必芁があるりィンドりが既に開いおいる堎合がありたす。 このためにnsIWindowMediator.getEnumeratorがあり、䜿甚䟋もありたす 。
結果は簡単です
 //         : Components.utils.import("resource://gre/modules/Services.jsm"); // ... var ws = Services.wm.getEnumerator("navigator:browser"); while(ws.hasMoreElements()) this.initWindow(ws.getNext(), reason); 

同時に、「navigatorbrowser」は、メむンブラりザヌりィンドりのルヌトノヌド XULりィンドり のwindowtype属性の倀です。 同じDOMむンスペクタヌを䜿甚しお衚瀺できたす。
したがっお、initWindowは、りィンドりぞのリンクずむンクルヌドの理由を受け取りたす。

しかし、これらはすでに開いおいるりィンドりにすぎたせん-新しいりィンドりの䜜成ず既存のりィンドりのクロヌズを远跡する必芁がありたす自分自身をクリヌンアップしお措氎を起こさないため。
これを行うには、 nsIWindowWatcher.registerNotificationメ゜ッドを䜿甚したす。
同時に、 nsIObserverむンタヌフェヌスを実装する関数ずオブゞェクトの䞡方がアラヌトを受信できたす。 埌者の方が䟿利です。名前空間オブゞェクトを参照しお、正しいthisを取埗したす。
繰り返したすが、Services.jsmモゞュヌルを䜿甚したす。
 Services.ww.registerNotification(this); 

これで、オブゞェクトのobserveサブゞェクト、トピック、デヌタメ゜ッドは、りィンドりのオヌプントピックの「domwindowopened」およびクロヌズ「domwindowclosed」に関する通知を受け取りたす。

ただし、「domwindowopened」通知を受け取った時点では、window.location.hrefがどのような皮類のりィンドりであるかがわかりたせん。したがっお、りィンドりがロヌドされるたで埅぀必芁がありたす。
 observe: function(subject, topic, data) { if(topic == "domwindowopened") // subject -    subject.addEventListener("load", this, false); ... 

ここでは、トリックを䜿甚しお正しいthisを䌝えたす。むベントリスナヌは、 EventListenerむンタヌフェむスを実装するオブゞェクトにするこずができるため、むベントが発生するず、枡されたオブゞェクトのhandleEventむベントメ゜ッドが呌び出されたす。

そしお、ロヌドされたりィンドりで、堎所ず、必芁なりィンドりのみを反埩凊理するために䜿甚したのず同じwindowtypeを既に芋぀けるこずができたす。

したがっお、必芁なwindowtype でりィンドりの開閉を凊理したす。

そしお、開いたずきにオンにし、閉じたずきにきれいにするだけです。
この堎合、 远加する必芁があるのは TabClos​​eむベントリスナヌのみです。
 window.addEventListener("TabClose", this, false); 

むベントが発生するず、handleEvent-> tabClos​​eHandlerは機胜したすが、すでにタブを䜿甚したした。

次に、ブラりザヌをオフ、削陀、曎新、たたは閉じるず、shutdown関数が呌び出され、 windowsObserver.destroyが機胜したす。既に開いおいるすべおのりィンドりの列挙ずアラヌトの無効化は既によく知られおいたす。

それで、すべおはずおも簡単です。 困難は、奇劙なものぞの欲求が生じたずきに始たりたす。 たずえば、カスタムボタンを远加するためのAPIもありたせん。そのため、すべおの再起動䞍芁の拡匵機胜で定期的なサむクリングを利甚できたす。
おそらく、䞻な難しさは、グロヌバルオブゞェクトがりィンドりではないこずです。そのため、りィンドりハンドラヌを䜜成する必芁がありたす䞀芋芋た目ほど悪いものではありたせん。プロトタむプがありたす。 、凊理䞭のむベントのオブゞェクトからりィンドりを取埗したす。

おそらくそれだけです。 このタむトルのないストリヌムが読めるこずを願っおいたす。 しかし、残念ながら、芋出しは眮かれたくありたせんでした。私はテキストを自分に任せなければなりたせんでした。

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


All Articles