源氏香 南知多

源氏香

前陣子去了一趟名古屋,一開始其實只是想說帶小孩去樂高樂園,結果行程規劃從一開始的名古屋市區和周邊為主,弄到後來變成市區五天租車五的,然後打算最後一天住在機場旁邊,就想說那前一天就在附近玩玩好了,要去的地方就因此多了一個一開始完全沒考慮過的「知多半島」了,當然也有研究住宿,當時也有找到「源氏香」這間旅館,不過那時候已經有安排了下呂溫泉的溫泉旅館,所以就沒考慮這個價位的住宿了,就在一切都安排好後沒幾天,突然就看到 FB 上有人分享到他們有特別的,針對台灣人的免費體驗方案,就是入住後要在 SNS 上分享。

閱讀「源氏香 南知多」全文

Sign-in with OOO ID

最近工作上在研究 Sign-in with Apple/Google ID,其實這件事情也作過很多次了,不過距離上次也有點久了,不知道那些 SDK 有沒有什麼改變,所以還是要重頭來,而且這次多研究了一個 Apple,有搞懂些以前沒釐清的細節,想說紀錄一下。

首先就是,我發現到 Google 和 Apple 現在都會回一個 ID Token,內容則是 JWT,而且是認真的 JWT,真的會有帶一點使用者資料(像是 email)的,可以用來作 user authentication(認證)用的,這在以前只有 OAuth 2.0 的時候是沒有的,查一陣子資料才發現這其實是 OpenID Connect(簡稱 OIDC) 規範的,該規範是是 2014 年發布的,其實還比 JWT 早定稿。

相較於 OAuth 2.0 做的是 authorization(授權),OIDC 做的則是 authentication(認證),只不過 OIDC 是整個依附在 OAuth 2.0 的架構上,利用的就是 OAuth 2.0 的 response_type,本來只有codetoken兩種,在 OIDC 多提供了 id_token,ID Token 是用 JWT,而且也有明確定義有裡面的 user profile 相關的欄位(不是定義哪些是必須提供,而是定義好語意和對應的欄位名稱)。

第二個則是我一直存疑已久的問題,就是 OAuth 2.0 的設計上基本是用 redirection flow,而且 redirect_uri 也是必要的,但是 Google 其實一直都支援純 JS 的方案,也就是說 Relying Party(應用程式端)不需要實作一個 redirection endpoint 來接資料,前端的 JS 就可以直接拿到 authorization code 和 access token,這次也認真的研究了這個問題,結果發現,Apple 的 OAuth 流程中,response_mode 給的值是目前不在標準內的web_message,而 Google 則是 redirect_uri 給的是一個沒見過的 scheme:storagerelay://的 URI。

其實我一開始以為這些設計,是各個公司自己想一想然後就自己做下去的,結果沒想到其實不是,首先是 Apple 的實作,用的是 OAuth 2.0 Web Message Response Mode 這份草稿的設計,這份草稿其中一位作者 Nat Sakimura 現在是 OpenID 的 chairman,而且他也是其他很多相關規範的作者(像是 JWT),不過這份草稿只有一版且沒人更新,有很多細節沒有寫定,大部分都是提供範例程式碼而已,所以 Apple 有些東西不是照範例做,例如 message 的 payload;Google 實作的則是 OAuth 2.0 IDP-IFrame-based Implicit Flow,這份文件其實是我最後才找到的,因為這份只有出現在 OpenID 的 mailing-list,而且也完全沒有討論和更新,不像前一份還有發到 IETF,回到文件內容,這份的作者,就全部都是 Google 的人了,內容完整許多,也有定義好 message 的 payload 結構,不過還是有些細節有缺,像是認證完成後的回傳事件,現在 Google 用的事件名稱在這份文件中就找不到。

除了這兩份草稿外,其實還有一份是 Curity 提出的 OAuth 2.0 Assisted Token,一樣有發到 IETF,而且還比較有在更新,最新一版是 2021 的,Assisted Token 的設計是多給了一個流程叫做 Assisted Token Flow,用不一樣的 URL 來使用這個 flow,這個流程的最後一步就是 postMessage 回到 opener/parent,規範寫的比較完整,包括各種新屬性的 registry、message 的 payload,還有安全性相關的考量都有,不過我看一看有些地方覺得有些疑惑,第一個是 message payload 的結構似乎辨識度沒很高,第二個則是完全沒提到 refresh token 和 authorization code,不確定是目前還沒考慮到那邊,還是因為安全性考量把它們先排除。

第三個是 Apple 的實作,雖然基本上還是照著 OAuth,但是其實限制更多,首先就是,scope就只有 email 和 name 可以拿,而且 Apple 做成,只有第一次 authorization 時,會把 user profile 傳給 RP,之後是拿不到的(不過 email 有在 id token 內),然後,雖然可以拿到 access token,但是其實完全沒有可以使用它的 API endpoint,所以什麼事情都不能作,真的只能用來做 authentication,最後一個,就是用 code 換 token 時,要給的client_secret參數還特別麻煩,要自己組一個 JWT(但是也因此會 expire 比較安全),然後用之前從 Apple Developer 後台生好的 secret key 去算 signature。

最後一個想紀錄的就是,這幾份標準和文件裡面幾乎都有一個章節是 Security Consideration,內容雖然不全面但是還蠻值得一看的,也有提到一些攻擊手法,而除此之外,其實還有一份文件:RFC6819: OAuth 2.0 Threat Model and Security Considerations,內容就是有說明 OAuth 2.0 各種設計在安全性上的考量(像是為什麼有 Refresh Token,什麼情境下它有助於安全性的提升),以及各種可能的攻擊手法。


Celeste

Celeste

一直想寫一篇關於 Celeste(蔚藍山脈)的文章,不過拖了很久一直寫不出來,其實我當初也是拖了很久才玩的。我因為原本就很喜歡 2D 的平台遊戲,然後看到 Celeste 的介紹覺得很特別,以登山為目標,沒有戰鬥但是有挑戰性的平台遊戲,多麼特別啊!所以 2019 年我就把它買下來了,還是 Limited Run Games 的版本,結果買回來後,稍微玩一下覺得怎麼難到爆炸,就放置了。

後來到了 2021 年底,在 FB 看到橘子說他登頂了,我才一點手癢一點不服輸的又重拾了起來,結果這次就順利了突破一開始的障礙,漸漸的上手了起來,後來橘子更是把全部的關卡包括第九章都過完了,本來想說我 B 面 C 面不勉強(有多難可以參考机核的文章:《蔚蓝:Celeste》:每个人心中都有一座山,但并非每个人都能登上山顶),結果還是不服輸的就慢慢的也都過完了,必須說這關卡難度的曲線設計的真的是非常棒,最後花了一個月左右,遊戲時間 50 多小時,成績是把全部關卡通過,收集到所有除了黃金草莓以外的草莓,認真的說,這遊戲真的很難,我相信一定很多人無法達到這樣的成績,當然我也不是要說我多厲害,因為我這樣的成績還不是全要素收集,更上一層還有無死通關的金草莓,不過這樣的挑戰歷程已經讓我想寫文章記錄下來了。

Celeste

我覺得這款遊戲最讓我感到厲害的,就是它遊戲的內外呼應,遊戲內的故事主軸是登山,而在了遊戲故事之外,這款遊戲也設計成了一個讓人攀登的高山,關卡和整體的難度就是設計的非常精巧,大家都可以在山腳出發,但是可能只有一半人能到五成高度,到了八成高度的地方就只剩下兩成,而真正能到達山頂,達成全要素,收集到所有的草莓,真正見到最後那個山頂風景的,就只有少數的那些玩家,那 26 個黃金草莓,全世界登記有案能拿到的大約只有三百多人台灣也有至少一位),Celeste 也有賣出一百萬套左右,也就說只有萬分之三的人,能夠到達這款遊戲的真正的山頂(要素的山頂、還有另一批人在拼 speed run)。

本來還想要介紹更多的東西,但是寫了兩三次都不盡如意,最後決定,留下這篇文章作為自己參與了這段挑戰的紀錄,我到現在偶爾,都還會拉出當時登山時的一些影片紀錄,有些關卡真的是非常困難,難到讓人過關時都忍不住會按下 Switch 的錄影按鍵紀錄下來,甚至也不少是功虧一簣的紀錄,當然,我拿到最後一顆 moon berry 的紀錄也有,當時也有貼在 FB 上。

附上幾篇開發相關的延伸閱讀:

其他延伸閱讀可以參考橘子的第二篇 FB 貼文。


digital envelope routines::unsupported

Node.js 16 LTS 已經結束維護,所以手上的東西就開始需要升級升級,然後就必須要來正面面對這個我逃避已久的錯誤訊息:

digital envelope routines::unsupported

這錯誤基本上就是發生在幾個網站的專案,尤其是 build 專案時特別會容易看到,而且這個錯誤其實和一般看到的 JS 錯誤長得不太一樣,全貌其實是這樣:

digital envelope routines::unsupported

Error: error:0308010C:digital envelope routines::unsupported

首先是錯誤訊息,前面有一些 hex 值,不知道是什麼,然後下面 trace 的地方,可以看到幾乎都是 node_module 內的東西,不是因為我們自己的 code 造成的,所以就很讓人困惑,想說是不是什麼系統問題、還是有什麼偷用非公開 API 造成不相容的狀況。總之以前就是遇到這個問題就是又降版回來,沒有仔細深究,這次終於要來認真處理,不過搜尋結果,幾乎都是說加一個--openssl-legacy-providerflag,都沒人說到底是什麼問題,尋找許久,終於在 StackOverflow 找到一則最正確的答案,沒想到和 OpenSSL 1.x 的生命已經到盡頭有關。

結果這個錯誤,其實是因為 Node.js 17 開始,從 OpenSSL 1.x 換到 3.x,然後 OpenSSL 3.x 不是向下相容的,所以有些東西有機會出錯,這邊爛掉的,其實是一些 legacy 的 hash method 預設是拿掉的,而 Webpack 在建立 bundle 檔案時,如果檔名有用到 hash 的話,預設的 hash method 用的就是已經被淘汰的 md4,然後 md4 是用 Node.js 的 crypto 來呼叫 OpenSSL 做事,Node.js 的文件也有提到支援的演算法是依據你的 OpenSSL 版本和系統而定,所以其實並沒有保證 md4 一定可以用,而如果使用了 OpenSSL 不支援的演算法,跑出來的錯誤訊息就是像上面截圖一樣特別了,然後我還特別去用 OpenSSL 3 cli 跑跑看,結果出來的錯誤訊息真的就是差不多:

OpenSSL 3 error

使用 flag 開啟舊演算法的支援其實我覺得還算可以接受,畢竟是 build 而已,不是拿來跑服務,不過這個 flag 似乎有點特殊,似乎不能直接放在NODE_OPTIONS裡面,而且同個程式庫要是拿到舊版 Node.js 環境去跑,加這個 flag 反而跑不起來,所以最理想還是把問題解決掉。

那這個問題應該怎麼處理呢?其實簡單說就是把套件升級升級就好了,因為現在的套件新版本都有處理這個問題,不過走上升級這條路之前可以先試試看 StackOverflow 上的解法(有可能讓你專案爛掉,請先備份):

npm audit fix --force

如果你用的是 yarn,沒有audit fix可用,但是也有人提供用 npm 來修理的流程,不過我是沒試過這個流程,我自己有一個專案是靠yarn upgrade升級後解決問題的(實際上是把所有有用到的 loader-utils 都升級到 2.0.4,本來有個套件用到 2.0.0),剩下的還是無法修好的就要靠手工了,然後因為我處理的網站只有 Gatsby 和 CRE(Create React App) 兩種,所以以下就是只有說明這兩個系統的為主,兩者其實都是使用 Webpack 作打包工具的,而 Webpack 是從 v5.61.0 開始保證支援 Node.js 17 的,我稍微查了一下 Gatsby 是從 4.2.0,而 CRA 的則是要最新版 react-script 5.0.1 才保證支援,為什麼說是保證呢?因為^的 semver range 的關係,例如要是你的 react-script 是 5.0.0,那你本地可能會是裝到 Webpack v5.60.0,那就不支援 Node.js 17 了,像我就是有 Gatsby 3.x 的,升級到 4.x 就沒事了。

Gatsby 和 CRA 其實都還好,最慘的是 eject 過的 CRA 了,只能手工升級,基本上就是去 react-script 那邊,複製需要的檔案回到你的專案覆蓋過去,最主要的是scripts/config/下的檔案,然後根據自己的修改紀錄把自己作過的修改改回去,接著更新package.json裡面的 dependencies,版本號就是參照 react-script 那邊的 package.json,最主要的就是webpack相關的,接著安裝套件後重新 build,要是還有一樣的錯誤,就看 trace 看看是哪個相依套件,看有沒有新版有修正就更新試試看,大概就是這樣,很容易漏東西所以會一直重複測試,蠻花時間的,不過最後 build 成功還是有成就感的。

PS. 還要小心其他升級的後遺症,如果是 app 最好要測試過各種行為,像我遇到 Webpack 5 不支援 polyfill Buffer 的問題,剛好那個錯誤又被 catch 掉,所以我 build 是沒問題的,就是測試跑不過,後來參考網路上的文章處理。


Vim License 的故事(下)

Vim License on choosealicense

接續前一篇

Mike 在 SPDX License List 這邊提出的問題則是,為什麼會有 Vim 要替換,但是 Vim Maintainer 不要替換這樣特別的情形,所以我就是認真的解釋,並且說明這是跟原作者 Bram 確認過的細節並附上討論,還有舉我前面提過那個最極端的例子,然後我猜最重要的是現實世界有沒有人這樣使用過,還好我還真的找到幾個專案有認真的把條款內的 Vim 替換掉(當然是連 Vim Maintainer 也換掉了),像是 Tagbar;我的 PR 是 2019/07/11 提的,然後一直來回到 9/25 回了最後一個回應之後就沒人回我了,之後到了 10/19 就突然被合併了(其實 SPDX 有定期的會議,應該是在其中有討論過要不要合併這個 PR 吧),接著等到 2020 一月我發了 PR 到 choosealicense 把 vim.txt 加進去,這次就蠻順利就合併了。

閱讀「Vim License 的故事(下)」全文

➡ 看看其它文章