瀏覽器指紋與反追蹤的思考

一直以來我就對網頁瀏覽器的各種 feature creep,還有瀏覽器的設計很有意見。一直以來有個想法就是各種網頁的 Javascript API (例如 WebGL, WebAudio 等等)應該要如同定位服務一樣,預設停用,需要使用時再由網頁向使用者提出請求,這樣的話就會增加網頁開發者的壓力不要去濫用這些功能,因為這些 API 一旦需要使用者批准才能使用,開發者就會一定程度上被迫去解釋為什麼他們需要存取這些 API。並且因為權限是動態給予的,就像手機應用程式的動態權限系統一樣,開發者就會有壓力去讓即使這些權限被拒絕的時候應用程式的其他部分能夠正常運作。

顯然現在的瀏覽器並不是這樣運作的,因此產生了一詭異的現象:瀏覽器開發者所設計的各種厲害功能,被網頁開發者主流所使用的方式,都不是瀏覽器開發者原本設計的目的,而是被拿來追蹤識別使用者。例如,當今 WebGL 的主流應用,並不是拿來在網頁上繪製 3D 圖形,而是讓網頁來獲取瀏覽器的特徵值,用於追蹤使用者。畢竟,實在沒有多少情境下需要讓網頁繪製 3D 圖形,對吧?

綜合上述原因,我自己目前使用者的瀏覽器是刻意停用 WebGL 和 WebAssembly 等功能的。

反追蹤 vs 不爽 feature creep

所以綜合起來我的初始目的有兩個:

  1. 反網頁追蹤
  2. 我就是不爽瀏覽器開一堆功能給網頁去濫用所以我要把這些功能關掉

第二個目的有時候會破壞第一個,因為把這些特定功能關掉的話可能會產生一個獨特的信號讓你變得更容易被追蹤。不過…就我一直以來的觀察,從來沒看過哪個追蹤程式會去慢慢測試每一個功能可不可以用然後回報這項資訊,大部分都是直接用那個 DOM 全域物件,但因為停用的關係全域物件是 undefined,於是整個追蹤器就丟 exception 然後壞掉。¯\_(ツ)_/¯

瀏覽器的反追蹤策略

根據爬文,目前主流瀏覽器的反追蹤策略有兩種

  1. 差異化:讓瀏覽器特徵對每一次瀏覽、每一個網站都看起來不一樣,Brave 採行這種策略,換句話說就是一個人每次看起來都像是不同人。
  2. 一致化:讓用同一個瀏覽器的不同用戶看起來一模一樣,無法分辨,Tor Browser 採行這種策略,換句話說就是每個人看起來都像同一個人。

但這兩種策略都有缺點:

  1. 差異化:
    • 並不是每一個會被收集的資料項目都那麼容易差異化,比如說 CPU 核心數,合理的範圍大概就只有 2~32 ,而且當中的奇數也幾乎不可能,例如 5, 7, 9。但這個說法我覺得不合理,因為本來就不需要去差異化所有資料項目啊,比如說顯然目前幾乎所有瀏覽器都支援 HTML 5,那差異化這個幹嘛?
    • 因為差異化一般是拿資料項目真正的值進行隨機演算,進階的追蹤器有可能可以透過多次收集數據獲得平均值拿來追蹤,因為取多次平均值可以抵消隨機演算的效果。這我覺得合理,但是我猜應該很少有追蹤器願意做到這個地步,因為成本還有效能考慮。
  2. 一致化的缺點就比較明顯了:
    • 有些東西一致化之後會降級使用者體驗,比如說所有人都必須要使用 UTC+0 時區、固定的視窗大小
    • 所屬的一致化群體必須要夠大才有意義

仔細思考

就反追蹤來說,瀏覽時最大的識別資訊其實是 IP 位置,而平常我並無意隱藏這項資訊。而想要隱藏 IP 位置的時候我會直接用另一個 profile (搭配 VPN)。

我想要反制低階追蹤,但不打算反制高階追蹤。但其實這麼說也不對,我其實並不介意讓低階追蹤程式得知我在使用 Linux,所以話說回來其實我介意的只是部分個別資料項目的敏感性,攻擊方想要結合已經公開的資料來追蹤我其實並不介意。甚至,我還蠻樂意讓追蹤程式知道,我正在使用 Linux 上面的 Firefox ,而且不支援 WebGL 呢,因為如果我偽裝成 Chrome + Windows 的話,觀測到的 Firefox 的市佔率不就更低了嗎,這樣廠商可能會覺得支援 Firefox 的必要性更低了。

Feature Creep

那我會在意的資料項目有什麼?

我不喜歡的功能,大致上都是可以讓網頁直接存取低階硬體的功能。例如 WASM, WebGL。如果網頁你說想要用 JavaScript 做一些特效、甚至整個應用程式邏輯(像是 Single Page Application),我甚至也都沒什麼意見。但如果網頁可以直接以接近原生應用程式的方式使用我的硬體,這 RCE(遠端代碼執行)的感覺就強烈了許多。雖然瀏覽器都還是對這些功能有很多限制,避免影響使用者的其他資料,但程式碼終究是在我的硬體上面執行,網頁上的 WASM 程式一開啟即執行的模式,我總有一種沒有被徵詢同意的感覺。

雖然說 Javascript 本身就算是一種 RCE ,不過這麼行之有年而且基本上離硬體很遠我就覺得…好像還可以接受。

啊不過或許 WASM 也離硬體很遠?有這個可能但我還沒仔細研究,但總不會比 Javascript 更遠吧?

難道我真的不在意網頁追蹤嗎?

思考到這個地步,不免問自己這個問題。其實也不是不介意,只是覺得,目前 Firefox 的基礎防跨站追蹤已經夠好了,對於更厲害能夠打敗基礎防追蹤的追蹤器,就日常使用來說,並沒有必要花費更大心思和忍受體驗降級去防它們。而偶爾進行一些不想要被追蹤到的瀏覽,打開 Tor Browser 就幾乎可以完美防禦了。

瀏覽器設定檔用途區分

經過以上思考,我把我的瀏覽行為和反追蹤需求分為下列幾種:

  1. 主要日常瀏覽、工作瀏覽:留下痕跡比較沒有關係的網站。
  2. 不想要跟日常瀏覽被關聯,但是留下本地瀏覽紀錄、維持登入沒關係的網站。主要是任何牽涉到線上付款或是購物的網站,這個設定檔我會打開 VPN(利用 vopono),除了 VPN 之外還要反追蹤。這主要是想要防止我的日常瀏覽行為和關鍵字被拿來推薦我要買什麼東西。
  3. 允許 feature creep (WebGL, WebAudio, etc) 的瀏覽器設定檔,這主要是給合理使用 WebGL, WebAudio 的網頁應用程式。
  4. 完全不想要留下紀錄的瀏覽,這個用 Tor browser 就好了。

實測 Firefox 的 privacy.resistFingerprinting (RFP)

RFP 用起來最大的麻煩就是,他為了要達成一致化,裡面的防追蹤功能是不能個別關閉的,因為如果允許關閉一部分的防追蹤功能,那這個特徵就可以被用於追蹤。

Firefox 開啟了 RFP 基本上就有與 Tor Browser 相同的防護。但以往的經驗是會讓瀏覽器變得很難用,所以這次再實測了一次,使用心得:

  • 不能為個別網站設定不同的放大縮小比率
  • Imperva 的 CAPTCHA 沒辦法正常顯示(拼圖的那個),只能改用聲音
  • 好像沒有了耶?!

其實意外地可用性非常高。

實際修改設定

依照上述的設定檔用途區分,我將他們調成:

  1. 不使用 RFP,啟用一些不影響使用體驗的隱私設定,還有關閉 feature creep
  2. 使用 RFP,使用 VPN
  3. 全預設

這次設定檔管理我改用 arkenfox ,因為他有個方便的 GUI 一次看所有設定。不過他與我之前使用的 pyllyukko/user.js 細節差異在哪還有待研究。

Jshelter

這次設定檔修改我都把 Jshelter 移除了,主要是因為速度變慢太多(可能是因為我同時也停用了 WASM),而且 CPU 使用率提高不少。除此之外幾乎所有 Cloudflare CAPTCHA 都過不去,不同網站的狀況不一樣,但過不去的意思是會直接寫「你的瀏覽器已經過期」,沒機會人工解 CAPTCHA。

當時決定使用 Jshelter 的理由是:

  • 它允許針對不同網站個別開啟和關閉不同防護
  • 網站嘗試收集瀏覽器特徵的時候會跳通知,也可以自己點開來看個別網站是不是有在收集瀏覽器特徵(它會給一個分數
  • 其實最初的理由還是因為我不喜歡 feature creep,但大部分 feature creep 沒辦法針對個別網站開關,如果用 Jshelter 的話就可以

Jshelter 基本上提供了類似於 Brave 的特徵值模糊化功能 (farbling)。

Jshelter 還提供了一個 Network Boundary Shield 功能,Firefox 目前似乎還對此沒有防護?Brave 說沒有,但實情有待研究。

參考資料

思考問題筆記

以下是我思考的時候問自己的一些問題和小結。

  • 如果我用的大部分網站已經是 logged in 狀態使用,那反追蹤似乎不太有需要
    • google
    • reddit
    • twitter
    • github
  • cloudflare 的 fingerprinting 太強制,如果嘗試用 jshelter 阻擋則完全過不了
    • 如果直接允許 cloudflare 做 fingerprinting 的意義是什麼?
    • 但如果讓我知道我被 cloudflare 阻擋了,至少我可以決定這個網站不值得看
  • Web worker 似乎有很多合理用途
  • webgl, webaudio 是被濫用來 fingerprint 的標準,實際上只有少數場合需要用到
    • 可以開另一個支援 webgl 的瀏覽器
  • 瀏覽器市佔率如何影響整件事?
  • 普通 fingerprinter 及 進階 fingerprinter ,何者為我目標?
  • 因為 captcha 太嚴格,沒有fingerprint無法通過,所以其實只要去確認fingerprint的資訊都是你覺得讓對方知道沒關係的資訊就可以了?
    • 比如說我覺得讓網站知道我偏好台灣中文其實沒關係
  • 有什麼 fingerprint 是難以隱藏的?

Building an existing Ubuntu package on Open Build Service

I’ve complained a lot on how the Snap version of Firefox sucks. In the end I found that it’s not possible to run Firefox snap in my own custom network namespace, so I decided to switch to the mozillateam PPA (had to configure APT pinning). But, just in case someday they stop updating the PPA too, I decided to learn to package my own Firefox. Turned out it was not that difficult!

Open Build Service

Open Build Service is provided by SUSE. It’s essentially a CI server for Linux packages. For me the advantages of using OBS are:

  1. OBS has all the package building environment set up, so I don’t have to set up my own.
  2. I don’t have to learn how to *build* the package. I can just download a source package from a PPA and upload it to OBS and it builds it for me.
  3. OBS provides package hosting as well. There’s no extra effort needed from me if I want to let somebody else use my package.

Technically I can also use PPA to achieve those as well, but OBS provides a possibility to also target other distributions. (It looks like a lot of work to configure that though.)

The source of my Firefox package can come from mozillateam PPA, Linux Mint, or PopOS.

OBS Concepts

OBS provides a User Guide, but I found that the openSUSE wiki gives a much better explanation around basic concepts in OBS.

Each project contains the resources needed to build one or more packages (i.e. RPMs/DEBs/etc.). These resources include source archives, patch files, spec files, etc. The output of a project is one or more repositories. A repository is an old familiar concept: simply a bunch of RPMs organized in a directory hierarchy along with some index/meta-data files that make it easy for tools like zypper to search and resolve dependencies.

  • Project: it’s also a namespace for configurations such as build constraints and build depedency preferences. Projects can have Subprojects, which is just an entirely separated project, only with similar names.
  • Repository: repositories can also be used as sources of other projects’ build dependency. The resulting package of a project’s build is also put into the project’s repository.

Each project is also essentially a version-controlled folder (in the folder are those resources mentioned above), managed by the osc commandline tool.

Importing an existing Debian package

I learned about the osc dput command from a talk at DebConf. But when running osc dput it complained “There is no sha256 sum for file _meta.". I worked around it by just downloading the source package files and running osc add on them.

Source package files contains:

  • <package_name_and_version>.dsc : the Debian source control file, which describes a package.
  • <package_name_and_version>.orig.tar.xz : archive file containing the original tarball (source code).
  • <package_name_and_version>.debian.tar.xz : archive file containing Debian build configurations, patches, changelogs, and so on.

After running osc add, run osc ci to commit and upload the changes.

Providing build dependency source repositories

Once uploaded, OBS will immediately start building the package. However it soon returned error saying that it couldn’t find some build dependencies. After rewatching the DebConf talk I realized I have to import the Ubuntu repositories.

After I manually added the update repo

At first, I simply clicked “Add from a Distribution". But OBS still complained that it couldn’t get new enough version of some build dependency. Then I realized that when adding Ubuntu:22.04, only universe is added but not update. A list of all repositories for Ubuntu 22.04 can be found here. I don’t know what universe-update is but I added it anyways.

OBS Project Configuration for Firefox

Two more things I had to change are the build constraints and prefer depedency settings.

Repotype: debian
Constraint: hardware:disk:size unit=G 30
Constraint: hardware:memory:size unit=G 8
Prefer: libncurses-dev
  • Constraint: constraints to the build worker machine. I took the information from here.
  • Prefer: when resolving build dependencies, when multiple packages fits the criteria, OBS doesn’t just randomly choose one out of them. You’re required to explicitly tell it which one to use. If I don’t specify, the build will show a warning message.
    • I checked apt policy libtinfo-dev on my machine and it shows that it’s only a transitional package. Therefore I selected the other option libncurses-dev.

All available project config options are here: https://openbuildservice.org/help/manuals/obs-user-guide/cha.obs.prjconfig.html

The build should be successful since we did not change anything from the original package. The build artifact (resulting package) will be available in the repository like at https://build.opensuse.org/repositories/home:pellaeon

Modifying the package

I will leave this for Part 2.

Firefox snap 依舊雷翻天,我不該浪費時間研究 snap 的,我錯了

把主力機升到 Ubuntu 22.04 之後,我這兩天繼續浪費時間搞 Firefox snap,目前 Firefox snap 主要的問題是:

  1. native messaging 不會動,導致 Mailvelope 這類的插件沒辦法和 snap 環境外的 gpg 程式溝通,不過官方好像已經有解法在 beta 了
  2. 我平常使用 Firefox 會分好幾個 profile ,不同 profile 過不同的 network namespace ,然後在 network namespace 裡面設定 VPN,整體使用 vopono https://github.com/jamesmcm/vopono 設定起來非常方便愉快,但是!snap 自己也有用自己的 network namespace 的樣子,所以只要在自己的 network namespace 裡面就無法使用 snap,我已經解掉很多問題成功把 firefox snap 跑起來了,但是最後還是卡在 snap 無法自訂 /etc/resolv.conf ,導致 firefox 無法使用 VPN 的 DNS server ,功敗垂成
  3. 即使界面語言選擇正體中文,仍然顯示英文給你看,這我就懶得修了,我就看英文吧,但這種低級的 bug 居然可以過 Mozilla 和 Canonical 的品管??

我跑去問了問題但還是沒有人回。

所以是時候拋棄 snap ,改用回傳統套件包的 firefox 了。

關於我 debug 在 netns 裡面跑 snap 的過程,我也有在論壇上記錄

套件包

我先試了 Linux Mint 的來源,好不容易把 APT pinning 搞定之後,要裝的時候發現 Linux Mint 的版本依賴 Mint 的 ubuntu-system-adjustments 套件,會做一些 Mint 自己的系統變更(比如說設定拒絕安裝 snapd,還有 grub 訊息改成 Linux Mint 之類的)。

所以,還是得要回去用 mozillateam 的 PPA

套件包 GPG 簽章設定

為了增加 Mint 的 APT 來源到我的系統,也要增加 Mint 的 GPG 公鑰,為此順便也學習了 apt-key 被棄用的原因。

簡單來說,原本的 apt-key 的設計是,匯入了一個簽章之後,這個簽章就是全域受信任的,不管套件的來源是哪一個 APT source ,只要有任何一個受信任公鑰的簽名,該套件就會被視為受信任的。這有一個嚴重的問題是,通常不同 APT 來源的發行者是不同人,自然也會擁有不同的簽章,但上面那個設計會導致任何一個受信任簽章持有人都可以發行一個和系統內某個套件同名的套件來蓋掉它

因此現在才改成將 GPG 公鑰寫入 /usr/share/keyrings ,然後額外在每個 APT source 裡面標注該來源使用的簽章:

deb [arch=amd64 signed-by=/usr/share/keyrings/signal-desktop-keyring.gpg] https://updates.signal.org/desktop/apt xenial main

Snap

垃圾爛系統,毫無客製選項和自由度,唯一會正常工作的情境是開發者想像中的一般使用者的環境,其餘情境下慘不忍睹。我不敢說預設設定的環境不常見,但會用 Linux 的人就是為了可以大幅度客製化自己的環境啊,所以有客製化環境的人所佔的比例肯定比 windows 和 macos 高很多。

Snap 這設計邏輯,堪稱微軟。看看微軟要不要趕快挖角一下 Snap 這垃圾,把它領走好不好,整個子系統都給微軟維護最適合不過了。

自己編譯 Firefox ?

過陣子再來自己研究看看…在 Reddit 上面看到有日本人之前自己維護的優化版 Firefox,似乎可以來自己研究一下怎麼修改編譯選項,改成一些適合我處理器的選項。gcc znver3 選項平均可以提升程式 11% 的效能呢

參考

不讓 Firefox 一啟動就載入所有分頁

上次評測各種分頁群組相關套件已經有兩個月左右了,後來我開了新的 Firefox Quantum 的 profile 測試 Experimental Simple Tab Groups 插件,沒什麼大問題,就逐漸很習慣地使用 Firefox Quantum 了。事隔兩個月再來做一個盤點,最近到底在用什麼插件。

Experimental Simple Tab Groups -> Simple Tab Groups

沒注意到,後來 Experimental Simple Tab Groups (ESTG) 就停止維護了, addons.mozilla.org 的套件頁面也刪掉了,看來也該轉移到新的 Simple Tab Groups (STG) 了,原本打算用匯出分頁群組的功能備份,然後再匯入新的 Simple Tab Groups ,但不知道為什麼點了匯出沒反應,可能是 user.js 我加了某些特殊設定的關係。

研究了一下,最後發現可以直接到 ESTG 插件的資料夾,把 storage.js 複製到 STG 的資料夾就可以了,兩個資料夾都在 profile 資料夾裡面的 browser-extension-data/ 裡面。(當然要記得備份 profile 資料夾免得出事。

LoadTabOnSelect

STG 還是有個麻煩地方,雖然可以設定離開分頁群組的時候自動 unload 裡面的分頁,但是只要進到某個分頁群組,裡面的所有分頁就會開始自動載入,一次吃掉大量資源。搜尋了一下,找到 STG 的 github 上面有相關的 issue ,推薦 LoadTabOnSelect 這個插件,就點開來安裝了。

Firefox 60 隱私及生產力設定

自從 Mozilla 2017 年釋出 Firefox 57 ,毀掉分頁群組和其他所有有用的插件之後,我就先跳去用 Waterfox 了。

後來我就持續不定時觀察各種分頁群組插件的完成度,是否達到接近 Quicksaver 本來做的 TabGroups 插件,上次做的調查是在 tabHide API 釋出不久之後,當時最好的選項 Simple Tab Groups 都還不是很好,我就沒有跳槽。

Firefox Quantum 首次通過勉強可用的測試

近期開始重新測試 Simple Tab Groups, 發現作者釋出了一個基於 tabHide 的實驗版本,短暫測試之後覺得還算可用,就先把工作用的 Profile 匯入到 Firefox Quantum + Experimental Simple Tab Groups 。測試的結論:

  • Experimental Simple Tab Groups 十分穩定,不會遺失分頁(這個 profile 有 50~100 個分頁,通常每次會同時開啟 10~20 個),切換方式也和以前差不多,速度也很快,整體來說沒什麼大問題
  • UnloadTabs: Firefox Quantum 沒有提供修改分頁標籤外觀的 WebExtensions API ,因此需要透過奇怪的 NativeExt 修改 UserChrome 樣式來達成這個效果,有點麻煩,我還沒試
  • Firefox Quantum 沒有比 Waterfox 快(這個 profile 和我的另一個更多分頁的 Waterfox profile 相比,插件也不一樣)
  • Firefox Quantum 會使用比 Waterfox 更多的程序(通常 Waterfox 只有兩個),總和起來吃掉比 Waterfox 更多的記憶體(沒有經過科學測量,只是我偶爾打開系統監視器看)
  • Firefox Quantum 在 MacOS 睡眠的時候似乎仍然會不斷 allocate 更多記憶體,但可能是因為睡眠停掉了某些作業系統的機制,吃掉更多的記憶體沒有被壓縮或是釋放,經常睡眠一個晚上起來就發現系統沒有反應,好不容易打開 Firefox Quantum 發現數個 process 吃掉 5GB 的記憶體。Waterfox 也有這個問題但比較輕微。

總結是勉強可以接受繼續用,畢竟 Waterfox 的安全性還是令我有點擔心,感覺維護人力不是很夠,我也沒時間去看他們有沒有真的 backport 每一個 mozilla 對 Firefox 做的 security patch 。

轉移更多 Profile

原本除了 Firefox 之外,我還有數十個 Chrome 的 profile ,拿來瀏覽比較不重要的網頁(like Facebook, Netflix) ,因為 Chrome 的 profile 切換比 Firefox 方便非常多。

但最近碰巧發現,Chrome 支援一個 Battery Status API ,讓網站可以得知使用者目前裝置的電力狀態,並且 Chrome 不提供任何設定的方法關閉這個 API ,Firefox 則是曾經釋出但是後來停止支援這個 API 。從這一案例,我看 Chrome 應該還有很多類似的缺陷,因此開始考慮轉移一些 chrome profile 到 Firefox 。

但考慮到我未來還有很多需求建立很多個 firefox profile ,因此開始 survey 一些適合所有 profile 都設定的選項,舉例來說:

  • 停用 WebGL :我沒有需要在瀏覽器裡面玩遊戲或是開這類型的網頁應用程式,而且 WebGL 可以拿來做 fingerprinting
  • 停用 WebAssembly :我非常反對的標準,你要快速的應用程式應該乖乖去開發原生應用程式。並且目前 Javascript 提供一定程度的原始碼透明性(雖然很多會混淆,但認真一點的話還是可以理解高階行為),WebAssembly 會把網頁應用程式變成一個黑盒子
  • WebVR :預設是停用的,但也是我用不到的功能
  • 停用 EME :我只要在要看 Netflix 的那個 profile 打開就好,其他 profile 沒必要開
  • 等等, Chrome 更誇張,連 WebUSB, WebBluetooth 都有了

整體來說,我覺得現在的網頁平臺越來越多 feature creep ,這些標準的支持者經常打著「Universal/ubiquitous platform」的名號,使用「網頁有跨平臺、快速發佈、使用簡單的優勢,因此應該讓網頁平臺支援更多應用程式功能,方便使用者及開發者」類似的論調。將網頁平臺視為一個應用程式發佈的管道我並不反對,然而當這些應用程式能夠存取越來越多底層作業系統的功能的時候,我不禁覺得,你們只是想要偷懶不去開發原生應用程式才來支持 web 增加功能,然而這卻越來越將 web 變成一個「任意程式碼執行的管道」,也賦予了瀏覽器越來越多本來應該是桌面環境要做的事情,這個是明顯的 Inner-platform effect anti-pattern

總之我自覺身為一個 web 的使用者,為了自己未來的利益(更好用、更安全的應用程式和網頁)著想,應該要抵制這些功能。

回歸到技術的解決方案,我最後找到 pyllyukko/user.js ,集合了幾乎所有我要的選項。我使用他的 relaxed 版本的 user.js 為基礎來修改,關掉更多安全選項以便利使用。修改後的結果放進我自己的設定檔 repo

我第一個轉移的 chrome profile 就是其中一個主要拿來看 facebook 的 profile 。因為我的 Firefox profile 太多了,因此我每一個都要選不同的佈景主題,方便我切換過去的時候知道這是哪一個。(不過 addons.mozilla.org 網站上面的佈景主題大部分都很醜,像長輩圖那種,再不然就很中二,要找到好的不容易,而且網站上面也沒有提供什麼方式可以簡單找到高品質的佈景主題)

插件

在新的這個 firefox profile 裡面,我裝了這些插件:

  • Experimental Simple Tab Groups
  • Privacy Badger
  • HTTPS Everywhere
  • Link Cleaner
  • Octotree
  • Snooze Tabs
  • Social Fixer for Facebook: 可以幫 fb 貼文標已讀,就不會一直出現重複的貼文,還可以以關鍵字過濾貼文,和各種強大的客製化功能
  • Flagfox
  • Facebook Container
  • Firefox Multi-Account Containers

Multi-account Containers 基本上是通用版的 Facebook container ,但它不會在你點 fb 上面的連結的時候把連結複製到另一個 container 開啟,查了一下發現兩個是可以並存的,所以我就讓他們並存了。另外 Experimental Simple Tab Groups 也有一個功能是把特定分頁群組指派成特定 container ,只要是那個 container 的分頁都會在那個群組開啟,也可以設定正規表達式抓取新開啟的分頁進到 container ,但後來想想我應該不需要同 container 的分頁都集中在一個群組,所以我就把兩個功能分開用了(就是不特別設定 simple tab groups 裡面的正規表達式)。

未解決的可用性問題

雖然研究了這麼多,但整體而言 Firefox Quantum 對我來說還是有很多可用性問題,尤其是當我轉移越來越多 profile (不管是從 chrome 或是 waterfox )過去,問題會越來越嚴重:

為什麼我不使用 container 功能取代 profile ?

  1. 因為這樣我就沒辦法「只開啟一部分(特定用途)的分頁」,我是照用途來分 profile 的(工作、閱讀新聞、閱讀文章、開發程式、開發網頁程式、學習科學、看影片、聽音樂等等),這樣我每次在做一件事情的時候只要開啟一個 profile ,不用就可以關掉,如果全部都擠在同一個 profile 的不同 container ,那一次全部開啟就很吃資源。

  2. 因為這樣沒辦法「只在有需要的時候啟用插件」,插件的安裝是跨 container 的,越多啟用的插件也表示越吃資源。然而我只有在看 Netflix 的時候需要啟用 NflxMultiSubs 、看 FB 的時候啟用 Social Fixer ,工作的時候啟用 Jitsi Meetings ,安裝的更多插件是資源的耗用,也是額外不必要的安全風險。

  3. 「特定網站在特定 container 開啟」的功能,在你有同個網站的一個以上的帳號的時候不適用,比如說 Facebook container 還是沒辦法同時登入兩個不同的 facebook 帳號。

一次開啟多個 Firefox profile 的問題

如果我在 Firefox Quantum 一次開啟很多個 profile ,每個 profile 的 Firefox 應用程式 instance 的圖示,都是 Firefox ,所以我的 Dock 上面就會有 N 個一模一樣的 Firefox 圖示,切換的時候根本不知道哪個是哪個……以前我都是用 Firefox-on-OS-X Label 這個 XUL 插件讓不同 Firefox profile 的 instance 的圖示顯示不同的 label ,但 XUL 插件被 mozilla 毀了,所以。

相容性

歡迎來到 2018 年,今年世界上的人類們還沒解決不同瀏覽器之間的相容性問題——哦,不過最近幾年不是微軟的錯了,是 Google 的錯。

  • Firefox 無法使用 U2F 登入 Google 帳號,儘管已經支援 U2F 協定,而且可以在 Github 上面用 U2F 登入, fuck you, google
  • Firefox 無法使用 Google Hangout (很不幸我還是得用這個服務),儘管 google 的說明文件表示支援 firefox ,這明顯是個謊言兒, fuck you, google

總結

Firefox Quantum 對我來說還是有重大的可用性問題,因此短期之內應該還是維持「不重要的網站用 Quantum 開,主要的使用還是在 Waterfox 」。

參考

TabHide 之後的分頁群組插件調查

Firefox 59.0a1 之後新增了大家等待已久的 TabHide 功能,所以我就來重新調查一次有什麼插件是符合我需求的了。我的希望是儘量能夠逼近 Quicksaver 原版 Tab Groups 的功能。

Conex

Conex 好像是 addons.mozilla.org 上面蠻熱門的類 Tab groups 插件,但我實測之後發現:

  1. 他的每一個分頁群組會存在一個 contextualIdentities 容器 (container) 裡面,這不合我的用途,因為
    1. 我已經把我的不同用途的 cookie store 放到不同的 Firefox 的 profile 裡面了,我希望我的所有分頁群組共用一個 cookie store。
    2. 這行為和本來 Quicksaver 的版本不一樣。
    3. 而且 contextualIdentities 我之前檢閱完之後就覺得是個設計、模組化不良的 API
  2. 似乎是因為用了 containers 的關係,建立新容器、改名容器需要到 Firefox 的設定頁面裡面手動改。

Simple Tab Groups

  1. 切換不同群組的時候,不在顯示中的群組裡面的分頁會被卸載

後來我研究了一下,發現這個插件切換分頁群組的功能完全是使用 tabs.remove() 來達成的,也就是切換的時候會把分頁關掉,換回來的時候再打開。目前他們有個 issue 是要實作切換群組的時候分頁不會被卸載

Panorama View

這個插件目前最接近我的需求,不同分頁群組使用同一個 cookie store 和 Quicksaver 的版本相比,缺少幾個功能:

  1. 清單(專屬的清單頁面或是 context menu )顯示分頁群組和群組中的分頁:正在開發中
  2. 在不同群組之間顯示一樣的釘選分頁:有 PR

另外幾個是我覺得可以加的功能,我有空研究的話可以加加看:

  1. 指定不同分頁群組的顏色,這樣會達到類似 containers 的顯示效果,但是仍然共用 cookie store 。可能可以重複利用 VivaldiFox 這個插件的程式碼來作出不同顏色。

其他

另外,閒逛的時候還發現了幾個有趣的插件:

  • Social Fixer: 各種 Facebook 延伸功能,可以過濾貼文、標示貼文為已讀、移除特定區塊等等。但可惜不是開源的。
  • Auto Tab Discard : 簡單的定時 unload 分頁套件,我在 57 前就有用其他類似的插件。

更新 2/10

我發現 Simple Tab Groups 雖然缺少最重要的功能,但是程式庫、國際化和 UI 比 Panorama View 完整。

 

Firefox extension 偵測新 URL 的載入

我想要寫出能夠偵測新頁面載入,並依 URL 附加特定 content script 的功能,目前試過用 page-modtabs 實做。

這是 page-mod
var data = require("self").data;
var pageMod = require("page-mod");
pageMod.PageMod({
include: /https?:\/\/www\.example\.com\/.+\/?$/,
contentScriptFile: [data.url("jquery-1.8.3.min.js"), data.url("read_aha.js")],
onAttach: function (worker) {
worker.port.on("testing", function (m) {
console.log(m);
});
}
});

這是 tabs
var data = require("self").data;
var tabs = require("tabs");
var { MatchPattern } = require("match-pattern");
var home_pattern = new MatchPattern(/https?:\/\/www\.example\.com\/?$/);
tabs.on('ready', function(tab) {
if ( home_pattern.test(tab.url) ) {
console.log('home_pattern matches!');
var worker = tab.attach({
contentScriptFile: [data.url("jquery-1.8.3.min.js"), data.url("read_aha.js")],
onMessage: function(msg) {
console.log(msg);
}
});
worker.port.on("testing", function(msg) {
console.log(msg);
});
}
});

兩個實做的功能相近,但是卻有不同的彈性與問題。

page-mod 的話,每一次 Firefox 送出新的 HTTP Request 就會進行比對,要是目標與 include 指定的 pattern 相符,就會觸發,載入 content script 。page-mod 麻煩的點在於,有時候請求的 URL 會包含一長串的 HTTP GET 參數,導致要設計 regular expression 的時候增加了很多複雜度。相對的,有一些網站頁面載入之後會自動移除那些 GET 參數,若是只需要偵測網址列 URL 的改變,那就簡單多了。

tabs 的話,則是偵測每一個分頁的網址列 URL 是否符合 pattern ,若符合才載入 content script 。但是我遇到很麻煩的問題是,對於使用者在網址列按 Enter 或重新整理的情況下,會觸發 pattern 檢查,但是若是使用者在頁面當中點了超連結,進入一個新的頁面,縱使網址列的 URL 已經改變,依然不會觸發檢查,因此 content script 永遠不可能被啓動。看起來用 tabs 的另一個好處是,相較於 page-modtabs 在檢查 pattern 時,可以引入其他的檢查條件,就在 if ( home_pattern.test(tab.url) ) 加上其他條件即可,我覺得未來我蠻有可能會用到其他檢查條件。

Stack Overflow 上面有人提到這個問題,乍看之下好像是無解,但是後來我查到用更低階的 XPCOM API 應該是可以做出這個功能,但是我還沒試。

Firefox Add-on SDK content script include

做個小筆記。

像是這樣:

pageMod.PageMod({
include: /https?:\/\/www\.example\.com\/.+\/?$/,
contentScriptFile: [data.url("jquery-1.8.3.min.js"), data.url("read_aha.js")],
onAttach: function (worker) {
worker.port.on("testing", function (m) {
console.log(m);
});
}
});

什麼時候會 include 這個 content script 呢?實驗發現

  • 當分頁 URL 符合這個 regex 的時候
  • 以下這些不會:
    • <link href="xxx.css">
    • XMLHttpRequest
  • 但是 <iframe> 會!