淺談 CSRF 與 CSRF Middleware
最近在我的 Zoraxy 開源專案那邊出現了這樣的一個 bug issue 他還很好的附了一個網頁測試介面的截圖 甚麼是 CSRF 攻擊? CSRF(Cross-Site Request Forgery,跨站請求偽造)是一種網絡攻擊技術,攻擊者通過在受害者不知情的情況下,冒充受害者的身份在受害者已經認證的網站上執行未經授權的操作。 CSRF 攻擊的工作原理 受害者登錄到可信網站:受害者首先登錄到一個需要認證的網站,在這例子是 Zoraxy 的後台管理頁面攻擊者製造惡意請求:攻擊者創建一個包含惡意請求的網頁或電子郵件,例如說這裡的一個 free burger 網頁 html + web form (action 或 form submit URL 指向 Zoraxy 的後台管理頁面)受害者訪問惡意鏈接:受害者在登錄狀態下 request 了攻擊者控制的網頁並提交了 web-form。執行未經授權的操作:由於受害者已經登錄(Auth Cookie 會跟著 form 一起送出去),Zoraxy webmin 介面會以為這些 request 是 valid 的,並執行相應的操作,例如上面例子的 toggle proxy 開關狀態 。 防禦 CSRF 攻擊的方法 CSRF Token:在每個受保護的操作請求中加入隨機生成的、唯一的 CSRF Token,並驗證這些 Token 以確保請求是合法的。檢查 Referer 和 Origin 頭:檢查 HTTP 頭中的 Referer 和 Origin 字段,確保請求是從合法的來源發出的。但是我在寫的是 Reverse proxy,本來 Referer 跟 origin 就是不可信的,所以不能使用此方法。雙重提交 Cookie:將 CSRF Token 存儲在 Cookie 中,並在請求中一起提交和驗證。使用 SameSite Cookie 屬性:設置 Cookie 的 SameSite 屬性為 Strict 或 Lax,限制跨站請求攜帶 Cookie。 說真的這也不是我第一次處理 csrf 問題。先前同一位使用者也對 ArozOS 提出過類似的 issue report。然而 ArozOS 因為是使用 agile 開發的,API 散落得到處都是,根本沒辦法用標準的方式來做 csrf middleware 來保護 API 接口,所以當時只用了一個非常不標準的方式來做(就是每一個 post request 之前都加一個要求 csrf token 的 ajax request,變成每個 request 都會變成要 request 2 次) csrf middleware csrf middleware 是一個 http Handler 並讓它來對 request 進行預處理並對不合規格的 POST (PUT / DELETE) 等 request 進行攔阻。所以這裡有兩個需要做的事情 在 HTML 頁面生成的時候,在頁面上加入一個 csrf token在有資料需要以 POST 等 request 回傳到伺服器時,在 payload 中以 header field 的方式附上頁面的 csrf token 在 ArozOS 的做法上,它是先對伺服器進行一個 csrf token generation request,然後再把 request 附到下一個 ajax POST request 裡面。這做法雖然不是不行,但是對於前端來說要改實在太複雜,而且一個 csrf token 又沒有那麼快 expire,不斷生的話只會浪費後端資源。 Production grade 的 csrf middleware 使用方法 由於 Zoraxy 的設計從一開始就按著標準的…
10 分鐘設定好 open web-ui 跟 ollama
open web-ui 是一個很方便的界面讓你可以像用 chat-GPT 那樣去跟 ollama 運行的模型對話。由於我最近收到一個 Zoraxy 的 bug report 指 open web-ui 經過 Zoraxy 進行 reverse proxy 之後出現問題,所以我就只好來裝裝看看並且嘗試 reproduce 出來了。 安裝 ollama 我這裡用的是 Debian,首先第一件事要做的當然就是安裝 ollama。教學在他們的網上有我這裡就直接寫 code 出來了。 https://ollama.com/download/linux curl -fsSL https://ollama.com/install.sh | sh 在執行這個 bash script 之後它會自動建立一個 systemd 的服務。預設 ollama 的 web server 只能透過 localhost loopback interface 存取,如果要透過其他網絡才能存取到 ollama 的 API 的話,我們就要讓它同時 listen to 其他的 network interface。最簡單直接的方式是把預設的 systemd service 檔案改成這樣: sudo systemctl stop ollama.service sudo systemctl edit ollama.service 然後在 service 檔案裡加入下面那行(見備注) ### Editing /etc/systemd/system/ollama.service.d/override.conf ### Anything between here and the comment below will become the new contents of the file # 加入下面這兩行 [Service] Environment="OLLAMA_HOST=0.0.0.0:11434" #下面的不要碰 ### Lines below this comment will be discarded ### /etc/systemd/system/ollama.service # [Unit] # Description=Ollama Service # After=network-online.target # # [Service] # ExecStart=/usr/local/bin/ollama serve # User=ollama # Group=ollama # Restart=always # RestartSec=3 # Environment="PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games" # # [Install] # WantedBy=default.target 儲存並退出之後重啟 ollama systemd 服務 sudo systemctl start ollama.service 抓模型 因為我比較喜歡用 CLI,所以我就直接透過 ssh 來順便把模型也載下來。這裡我在試玩的是 qwen:https://ollama.com/library/qwen 一般模型也會有不同大小,而我選這個是因為我要省空間(對,SSD 快要炸了),所以我就選了比較小的 1.8b 版本。你可以用這個指令來讓 ollama 準備這個模型: ollama run qwen:1.8b 如果要其他大小的模型的話,只要把後面的 1.8b 換成 4b / 7b 之類的就好了。另外比較有名的包含 llama3 之類也是可以透過這樣的方式下載。 值得一提 如果你的 root disk (Linux 的 / 或是 Windows 的 C: 硬碟)不夠空間跑你想測試的模型,你可以在啟動 ollama…
SEO 快速上手筆記
作為經營好幾個中小型的 Open Source Project website 的開發者,間中也會收到一些來自不同國家的 SEO 公司的垃圾郵件,說甚麼可以幫你把網站最佳化到上 Google 首頁結果之類的。首先,有幾點我要先說明 沒人知道 Google 的 Search Engine 排名演算法,而且很可能他們也是用 AI 來做的,他們自己的員工也不知道SEO 本身只是在 HTML file 的 head section 裡加一些 metadata 等級的簡單作業而已。就算要弄的話如果本身你會一點 HTML 跟知道要加甚麼 meta tag 的話其實也就一兩個小時的工作量就能做到外面公司的 80 - 90% 有效度。想在 Google 出第一個結果的最佳方法是幫你的產品改一個 Google Search 沒結果的名字(真的,不相信的話你去 Google 找 "Zoraxy" 看看,第一項應該就會出現我的 Zoraxy project 了,而那個 github page 根本除了 OG 以外沒做 SEO) 那正文要來了囉 HTML Head 結構 HTML Header 是一個簡單的 HTML tag。一般的話大概長這樣 <!DOCTYPE html> <html> <head> <!-- 這裡就是 Head 的部分--> </head> <body> </body> </html> 那一個完整,有做 SEO 的 head 會長怎樣呢?我們來看這個範例 <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="format-detection" content="telephone=no,email=no,address=no"> <title>托比的神奇蹦蹦主頁</title> <!-- HTML Meta Tags --> <title>imuslab</title> <meta name="description" content="創客產品與開源軟體項目,還有方便好用的各種網上小工具 | Archive of tobychui's maker products and open source projects, with online tools and service for myself but also for anyone who visited my site"> <!-- Facebook Meta Tags --> <meta property="og:url" content="https://imuslab.com"> <meta property="og:type" content="website"> <meta property="og:title" content="imuslab"> <meta property="og:description" content="創客產品與開源軟體項目,還有方便好用的各種網上小工具 | Archive of tobychui's maker products and open source projects, with online tools and service for myself but also for anyone who visited my site"> <meta property="og:image" content="https://imuslab.com/index/og.png"> <!-- Twitter Meta Tags --> <meta name="twitter:card"…
Zoraxy v3 – 適合新手的反向代理伺服器
最近我一直在進行相當多的 Zoraxy 更新。對於從未聽過 Zoraxy 的人來說,它是我的開源反向代理伺服器 (Reverse Proxy Server)。可以部署在你的 homelab 或server / NAS 裡面。 如果你對 Zoraxy 如何運作沒有興趣,單純是來找一個可以在 Windows 和 Linux 上運行的 Reverse Proxy Server,請按這裡。 v3 的新功能? 嗯,如果你之前使用過 Zoraxy v2,每次打開 Web 管理界面,你都會感到一陣沮喪的感覺。這是因為在開發 v2 的過程中,我沒有多餘的時間仔細考慮配色方案或設計一個具吸引力的界面配色(然而作為開源項目來說,這界面已經算是到達夠好 + 能用的設計)。 v2 homepage v2 的代理清單 現在 v3 長這個樣子 除了界面更新之外,Zoraxy 還添加了大量新功能,以 optimize proxy core 的功能(或者我可以說,因為有太多 user 是從 Nginx Proxy Manager(NPM)轉過來用 Zoraxy,所以有一些部分如果盡量接近 NPM 的設計會省下我很多處理 issue 的麻煩)。一般來說,這不是 NPM 的替代品,而更像是一個讓你更容易在測試和debug 時切換 endpoint 的 Reverse Proxy。但無論如何,我不介意人們提出感覺像 NPM 的 enhancement issues。 Default Site 在 Zoraxy v3 中,我們新增了對 Default Site 和多個 host name 的支援。 Zoraxy 的前身(名為“Web Proxy”,是 ArozOS 系統的一個子服務)設計僅用於處理單一域名的反向代理,v2 版本添加了對子域和其他主機名的支援,但由於是沒經過設計加進去的,所以對 user 來說有夠混亂( 使用者對 “Proxy ”、“Subdomain” 和 “Proxy Root” 的設定感到困惑然後又跑來開 issue。這就是為什麼在 v3 的設計中,我設計一個新的界面和設置邏輯。有了Default Site 的選項(對,就是 NPM 那個),那習慣用 NPM 的人可以輕鬆地切換到 Zoraxy 了。(順帶省下了我很多解釋東西怎樣用的時間) Default Site 提供 4 個選項供選擇。對於新手來說,你可能想要使用內部靜態網頁伺服器,在使用 "Static Web Server" 功能時將一個 "index.html" 文件作為你的網站首頁。這更像是傳統的 Apache 的用法,如果在 apache.conf 中沒有對應的 Virtual Host,所有的路由都會進入內置的靜態網頁伺服器,並從你的 /var/www/html 資料夾抓檔案來回應 request。 Redirection 和 404 Not Found 用起來也相對直接。對於 Redirection (重定向),你可以輸入要重定向的目標域名/IP 地址。在要將舊的(子)域名指向新域名,或者直接阻止那些未知/過時子域名的請求時滿有用的。 Wildcard 域名證書與 SNI 在 v3 中,我們 implement 了 TLS/SSL 證書查找邏輯中的 SNI。Zoraxy SNI 與其他 implementation 的區別在於,它不需要用戶輸入來將證書與特定主機名“鏈接”起來,而是會自動掃描並 serve 出對應的 TLS certificate。 在 v2 中,用戶需要手動為每個證書設置與匹配的域名。例如,如果你有一個證書可以涵蓋 a.example.com 和 b.example.com,你需要手動將其匹配關鍵字設置為 "example.com",才能使這個域名的 TLS 加密正常工作(不然會出現 self sign certificate error)。現在有了 Zoraxy v3 的自動證書查找邏輯,你不需要設定任何東西。只需上傳你的證書(或使用內置的 ACME 工具從你選擇的 CA 生成一個),Zoraxy 將自動解析並選擇正確的 certificate。唯一的限制是對於包含多個主機名的證書(例如 domain.com 和 anotherdomain.com),速度會稍微慢一些(可能需要 O(n)…
Concurrent & Racing Conditions (並發與競態條件)
最近因為我在開發 Zoraxy 時需要設計一個可以做到 high speed concurrent READ 跟間中 write 的 map,跟另一位高雄的工程師大佬討論了一個晚上,後來我發現原來滿多人對 concurrent / racing conditions 的處理有一定程度的誤解,所以我就來簡單的解釋一下最常見的誤解 - Check for locking。 問題 假設你有兩個 process,一邊要讀取一個無法同時讀寫的 map 資料結構(例如 Go 的 map[string]struct{}),另一個要寫入新的 key 到同一個 map。由於 map 並沒辦法處理 concurrent R/W,所以你要怎樣做呢? 解決方法 1:改用專用的 concurrent map (如 Go 的 sync.Map) 這個解決方法簡單直接,我就不再詳細解釋了。然而由於我在開發 Zoraxy 的 high concurrent access 特質,使用 sync.Map 的話會做成很高的 over-head,因此我並不是很想用它(但是也不影響 sync.Map 作為沒法解決時用的最後方案的決定) 解決方法 2:mutex lock 這算是比較正規的方案之一。在讀取和寫入之前先對 map (或是 slice) 進行鎖定,然後在寫入或讀取之後解鎖。這樣就能確保同時間只有一個 process 對這個 map 有 R/W access。但是這同時也會產生另一個問題,就是在 read lock 了之後,假設有另一個 process 也想同時進行讀取的話就必須要等前面的讀完,因此這個方案對於高並發的 request handling 來說並不是太有效率。 那聽到這裡的時候很多人會直覺的覺得:那只有 write 的時候 lock 就好啦,read 的時候檢查 map 是不是被 lock,沒 lock 的話就讀取。由於檢查的時候不會 lock,因此其他需要 read 的 process 也不會被擋不是嗎? 聽上去好像沒錯喔?讓我簡單寫一個 pseudocode 例子: function write(){ mutex.lock() map.write("foo", "bar") mutex.unlock() } function read(){ if (!mutex.isLocked()){ //Map is not locked var value = map.read("foo") print(value) }else{ //Map is locked, retry after 100ms delay(100) read() } } mutex 的部分可以是 programming language 自帶的 mutex 功能或是簡單的 boolean,效果都是一樣的。但是如果你有注意到,你不會找到 mutex.isLocked() 這個功能。 如果你需要用到這個,很大機會你寫錯了 這是為甚麼呢?那是因為 OS 層基本運作原理所引起的。這裡對於本科沒修 Computer Architecture (計算機架構)的工程師可能比較難理解。簡單來說就是,CPU 上就只有 n 個核心,但是你的作業系統上面有很多東西在執行,所以 OS 會對上面執行的工作(process)進行快速切換。每次切換的時候因為速度很快,所以會讓你有一種它們在並行處理的感覺。而實質上,每個 process switching 都會有一個 overhead,而這個 overhead 就是為甚麼 mutex lock 沒辦法被用於檢查的原因。 其中一種常用的 scheduling 演算法:Round Robin Process Switching 關於 CPU scheduling 跟 scheduling 演算法的詳情可以看這邊 所以為甚麼 Mutex 不能檢查是不是被其他 process 鎖上? 當你去檢查一個 mutex 是否被鎖的時候,檢查當下可能沒被鎖,但是檢查完到執行下一個邏輯的時候可能已經被另一個 process 鎖上了…
從零開始自幹房間自動化燈光系統(Part 1)
說到我房間裡的 IoT 控制系統,從 2021 年起我就一直在用一套自己開發的 IoT 協議名為 Home Dynamic。這套系統的原理和詳情可在我另一篇文章( 從零開始的 IoT 系統設計 )裡找到,但是簡單來說它就是一個很簡單的 HTTP RESTful request 模型下的迷你 IoT 系統,可以用於開關電燈和透過 Tasmota firmware 來控制幾個 Sonoff 的 WiFi Smart Switch 而已。 到最近,因為我香港的房間要整修,所以我就把房間裡有點 hacky 的系統升級到新的自動化系統。Home Dynamic v2 (簡稱 HDSv2)雖然在設計的時候已經有考慮到很多不同的使用場景和可能出現的問題(如 off grid control,伺服器 / relay 的 SPOF 等等),但是其控制 latency 總是讓我覺得有點煩惱。即使後來 ArozOS 改用 Golang 重寫,從按按鈕到電燈真的亮起的時間大概也只是在 2 - 3 秒內,這個速度跟我去按一個物理開關還是有很明顯的差別。所以在新裝潢的房間裡,我採用了一個更新版本的 HDS 協議來開發我的新自動化系統,現在我把它暫稱為 HDSv3。 控制器硬體部分 那說到 IoT 跟自動化,在提軟體之前一定要先講講硬體。畢竟只要硬體夠強,軟體再爛也是能跑得很順暢(望向 python) 。這次為了未來的擴展性和標準化,這次我選用了半工業級的硬體。下圖中是我用的繼電器模組,是一片市售的 4 路 WiFi 繼電器模組。它是使用 ESP12E 作為主控制器,跟先前的 HDSv2 一樣都是基於相同的 MCU。因此大部分 HDSv2 的源碼能夠直接移植到 v3 然後下載到這片板子上。雖然這片東西可以使用 110 - 220V 輸入,但是因為我原先整套系統都是用 24V 的,因此這部分的機能就白白被我浪費掉了( 那當然,這片東西不能就這樣放在我的桌面上。因此我買了一個 DIN Rail 用的外殼,然後把整個組好的安裝到 DIN Rail 上。 現時的照明控制系統 那你可能會好奇,既然是控制燈光,那一個簡單的繼電器模組就可以做到了。旁邊那兩個盒子又是甚麼? 如果你仔細看一下那個繼電器模組的照片,你就會發現那個模組真的單純在做切換而已,它本身並沒有供電能力。所以為了讓接上去的 LED 燈條有電力供應,就必須透過另一個裝置為 Relay 的 NO (Normally Open)端供電。這裡中間的模組就是作為一個 power distribution hub 的用法來提供 4 個相同於 Vin 的輸出和 3 個可調節的輸出。 大概原理 而最左邊的是 LED strip 的限流模組,大概就是因為 24V 的燈條用 24V 供電的話會太光,所以那個小黑色模組裡面是一個簡單的 XL6009 自動升降壓模組來把電壓調整到大約 19.2V (我喜歡的亮度) 原本是長這樣的,後來想了想還是把它放到 DIN Rail 上比較好 軟體與控制部分 講到軟體部分,就不得不提一下 IoT 技術了。說真的,雖然我知道很多不同的 IoT 通訊協議,從 MQTT(DIY 很多人用,基於 TCP/IP)、 Zigbee (IKEA 那套)到工業用的 RS485 / RS232 之類的,我還是比較喜歡用 2.4Ghz WiFi。雖然距離短、用電量高,但是本來我的裝置就是用來控制電源的(aka 長期會有電源供應),加上香港地方實在太少,我想盡量省下一個放 hub 的空間 + 本身房間已經有 WiFi 覆蓋,所以自然地 WiFi 是最好的選擇,所以我還是選擇了基於 TCP/IP 的協議。 考慮到設備的相容性、不用額外安裝程式便能控制等優點,在眾多基於 TCP/IP 的協議下我選擇了 RESTFUL。一來是所有手機都有網頁瀏覽器,即使伺服器炸掉只要有一台手機能連接到同一網絡便可以透過 p2p 的方式控制 IoT 裝置。另一個好處是 RESTFUL API 實在太通用了,從 ESPHome 到 Home Assitant,最好支援的裝置類型依然是基於 RESTFUL API 的裝置,再加上怎樣看 HTTP request 這東西在未來 10 年應該都會還存在(畢竟是 Web 技術的基礎),選它一定沒錯( 而為了解決…
在 Linux 上建立一個有容量限制的資料夾
最近我在研究 mdadm 的時候無意中發現了一個可以依靠 losetup 和 partition 映像檔的神奇方法來建立一個具有容量限制的資料夾。所以就寫這篇來簡單記錄一下。 好,可是這有甚麼用? 之前我在開發 ArozOS 的時候想著給使用者建立一個 storage quota。本來想著用 linux 的 File System 來 implement 這個功能,可是找了很久之後發現方法都很麻煩或是過於複雜(例如依賴一些特別的 file system format / container)。所以如果剛好你想設置一個 hard limit 給一些軟體來做 buffer / upload 之類的,都可以考慮這個方法。 首先,建立一個映像檔 我們第一件事情要做的就是建立一個固定大小的映像檔。以我這裡為例,我建立了一個 64MB 的映像檔來模擬一個硬碟 partition。 bs 是 block size,就是系統會 buffer 多少 data 才會真正寫進去這個(block )device,這裡用的是 4MB。 count 是這個虛擬硬碟裡有多少個 block,16 個 4MB 的 block 加起來就是 64MB 啦 sudo dd if/dev/zero of=sdX.img bs=4M count=16 至於 /dev/zero 是甚麼,它是一個只會不斷吐出 0 的 byte stream。你可以把它當成一個無限大的檔案,裡面只存在無限個 0。透過 dd 指令,我們就可以把需要的 0 bit 從這個檔案裡 clone 出來來建立我們需要的映像檔大小。 之後:建立檔案系統 在建立了一個空白的映像檔之後,透過 ls 指令我們可以看到新鮮的 .img 檔出現了。 aroz@orangepizero2:~/raidtest$ ls sdX.img 然後我們就是需要對它進行格式化,就古人所說 Everything is a file Linus Torvalds did not say this 所以我們可以直接對它用 mkfs 跟 mount 指令。假設我們有一個叫 sdX/ 的資料夾,那我們就可以把映像檔格式化之後掛到那個資料夾。 // 建立掛載點 aroz@orangepizero2:~/raidtest$ mkdir sdX //用 ext4 把映像檔格式化 aroz@orangepizero2:~/raidtest$ sudo mkfs.ext4 sdX.img mke2fs 1.47.0 (5-Feb-2023) Discarding device blocks: done Creating filesystem with 65536 1k blocks and 16384 inodes Filesystem UUID: bf600d34-c93a-48bc-ad27-27255fbd1333 Superblock backups stored on blocks: 8193, 24577, 40961, 57345 Allocating group tables: done Writing inode tables: done Creating journal (4096 blocks): done Writing superblocks and filesystem accounting information: done //檢查看看是不是需要的資料夾和檔案都存在 aroz@orangepizero2:~/raidtest$ ls sdX sdX.img //把映像檔掛上去 aroz@orangepizero2:~/raidtest$ sudo mount sdX.img ./sdX 之後我們就可以在 df 裡看到掛載的虛擬硬碟 /…
在 Zoraxy 加入 TLS SNI 功能
最近我在開發的 Zoraxy v3 在我開發 Zoraxy 之前我也不知道 https 證書這東西對於 reverse proxy 伺服器來說到底有多複雜。一開始的時候因為我都是用一個域名(domain name),所以 reverse proxy 裡面也是只需要處理一個主機名稱(host name)。而初代的 Zoraxy 則是直接用 TLS hello info 裡面的 server name 作為 certificate 的 key 來找到合適的 certificate 並回傳給客戶端,所以時間複雜度(time complexity)而言是 O(1) 的速度。換成程式碼大概長這樣: http.ListenAndServeTLS(":443", "server.crt", "server.key", nil) 到後來發現 virtual directory 帶來的麻煩後,Zoraxy v2 加入了 sub-domain 的支援。為了解決找 certificate 的問題, v2 的做法是讓使用者把每個 sub-domain 都 map 到一張 certificate 上面,所以結果就是同一個域名下會有很多張證書(例如說 a.example.com 會有 a.example.com 的證書、b.example.com 會有 b.example.com 的證書)。這樣設計的好處是一來找 certificate 的演算法比較簡單,二來我們可以根據 hello info 的 server name 進行也是 O(1) 時間複雜度的 certificate lookup,不用任何存取 file system 的 loop 便可以直接找到證書。 if fileExists(helloInfo.ServerName+".pem") && fileExists( helloInfo.ServerName+".key") { //Direct hit pubKey = helloInfo.ServerName+".pem" priKey = helloInfo.ServerName+".key" } 然後在 Zoraxy v2 用了這一年多之後就又出現問題了。coauthor 的其中一張證書裡面包含了幾個不同的 domain 跟 subdomain,也有使用者的證書是含 wildcard 的,也有是舊版用 Common Name 來定義(而不是 DNS entry)來標記 host name 的,結果就是一大堆 issue 就出現在 repo 上面。 SNI 的基本概念 SNI 的原理大概就是由伺服器端跟據 TLS Hello Info 的 Server Name 來自動回傳合適的 certificate 給 Client (這裡因為 Zoraxy 是一個 http proxy,那我就以瀏覽器為 client 的例子)。對於很直接的域名例如說 v1 跟 v2 裡面出現的,基本上就是只要把 certificate map 到一個 string 轉 certificate 的資料結構裡面就可以了。但是對於 v3 之後的複雜案例,則是需要一些更複雜的邏輯來處理。 相信來得我部落格的人不是工程師應該都是技術大佬,所以我就直接把 code 拿出來講好了。這裡是 Zoraxy v3 TLS 解釋器裡面最重要的 function func(m * Manager) CertMatchExists(serverName string) bool { for _, certCacheEntry: = range m.LoadedCerts { if certCacheEntry.Cert.VerifyHostname(serverName) == nil || certCacheEntry.Cert.Issuer.CommonName ==…
ArozOS 的桌面大更新
之前有一段時間我都在想幫 ArozOS 的桌面做一個大更新,把最頂部的仿 Ubuntu 狀態欄拿掉,可是因為開刀和學業上各種事情一直沒空完成。最近新年前剛好指導教授不在一個禮拜,所以我就來更新了一下這個久久沒時間完成的小目標。 原先 web-desktop 的界面,上下都有一個黑色的功能欄 新的 web-desktop 界面,最頂部實色的被整合到下方的欄內 日曆和通知也被移到右下方 右下方角落的那個圈圈就是以前在右上方的背景執行工作列表 其中我最喜歡的功能大概就是這個系統一覽表了。從伺服器的在線狀態,名稱,SMART 狀態到各顆硬碟的使用量都能夠直接看清楚。 嘛當然除了這個以外還加入了很多微細的使用者體驗最佳化,例如說背景加深 + 模糊的狀態來突顯某個元件之類的 未打開日曆前的背景 打開日曆後加入的 backdrop-filter blur,突出了日曆和通知欄的前置感 另外也加入了能直接進入進階分享設定的功能按鈕,比起以往要進入到 File Manager 來更改進階設定要來得更方便。 這樣的界面大概已經算得上是追到近年的 web-desktop 界面水平了吧?雖然說在 github web-desktop 的分類排行中 ArozOS 是掉到了第四位,但是以完整性來說 ArozOS 還是跟 DSM 比得上的 web-desktop 類界面(
Golang – 加速抓資料夾的總大小的方法
最近因為一些意外所以要頻繁跑醫院回診,結果就是在等待跟來回的時間前後多了很多零碎的時間,所以我就不浪費這些時間來幫我用了快 6 - 7 年的 ArozOS 系統做了點更新了。但是這篇部落格並不是在講我更新了甚麼(雖然某程度上也是),而是講一下關於 Golang 處理 exec 輸出的一個小發現。 背景故事 - ArozOS 的 Disk Properties 載很慢 ArozOS 的 Disk Properties ArozOS 因為採用半虛擬磁碟架構的設計,所以每次要列出 disk space 的時候,除了一般像 Windows 那樣會列出用了多少跟全部空間是多少以外,如果磁碟空間是使用者分隔的,就要多計算使用者佔用的空間比(圖上黃色條) 這個功能原本是使用 Walk function 來實現的。因為 ArozOS 的 vfs architecture 關系,這裡我使用的是 ArozOS 專用的 filepath module (你可以把它想像成 Go 原本的 filepath.Walk var size int64 = 0 fshAbs.Walk(rpath, func(_ string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { size += info.Size() } return err }) filesize = size fshAbs 是 file system handler abstraction 的意思,大概就是「這個虛擬磁碟的檔案系統層」的 object。 另外 rpath 就是從 user space translate 過來到這個 abstraction layer 的實質路徑,如果是本機磁碟的話就會是好像 /media/storage1/users/{username}/myfile.txt 這樣的 path;如果是 network drive 的話會是跟 mount-point 的相對路徑,例如 WebDAV 或是 FTP 下就可能會出現 /myfile.txt,或是 SMB 下的 /Share/myfile.txt 之類。 這樣的 implementation 你一看就可以知道這個在 Network Drive 上是不可能實現的,因為每一個檔案 Go 都要抓它的 Stat,即是遠端有多少個檔案就會送多少個 file request 過去,所以自很早之前就 ArozOS 的 File Manager 就加入了 這個簡單粗暴的解決方法… if fsh.IsNetworkDrive() { filesize = -1 } 然而隨著我在用的 NAS 東西越來越多,這個 walk function 即使在 local disk 下也開始變得很慢。 那改用 kernel 內置的 API 來抓不就好了嗎? 確實如此。Linux kernel 裡其實有內置一個滿好用的指令叫 du,用起來也超簡單,只要: du -sb /media/storage1 481491222874 /media/storage1 那這個資料夾總大小(byte size)就出來了。如果你想要 block size 的話可以把 b 去掉。然後就是寫一個簡單的 Go function 去把資料抓出來。 /* Get Directory Size with native…
目前第 1 頁,共有 11 頁