筆記:Firebase functions with authentication

主要可以 trigger 兩個,一個是 onCreate,一個是 onDelete

onCreate 在以下情況會被觸發

  • A user creates an email account and password.
  • A user signs in for the first time using a federated identity provider.
  • The developer creates an account using the Firebase Admin SDK.
  • A user signs in to a new anonymous auth session for the first time.
exports.sendWelcomeEmail = functions.auth.user().onCreate((user) => {
  // ...
});


onDelete 在使用者被刪除時觸發

exports.sendByeEmail = functions.auth.user().onDelete((user) => {
  // ...
});

裡面的 user 主要就是 UserRecord

email / displayName / customClaims / uid / …. 等欄位都有。

onDelete 可以用來做刪除 firestore/realtime database 上的資料,需要考慮 functions 能執行多久。

修改 git commit 的 author name

因為 commit 時的作者身份錯亂,所以要改掉。在 StackOverflow 查到這篇:How to change the commit author for one specific commit?

  1. 先 git rebase -i ,然後把 pick 全改成 edit
  2. 接著,git 會切到第一個 commit 結束的時間點
  3. 輸入 git commit –amend —author=”Author Name <email@address.com>” –no-edit ,這樣就會把這次 commit 的 author 修改為 Author Name <email@address.com> 。對,別忘了,這邊要改成你自己的名字跟 e-mail 。
  4. 再輸入 git rebase –continue 切到下個 commit
  5. 就這樣依序作業直到結束。

很麻煩,如果有上千個 commit 的話….(眼神死),所以以後還是要把 author 設定好,否則又要再苦一次。

axios catch

一般是寫 .catch((err) => {console.log(err);}

這樣只會看到 http status 的錯誤,不能取得 response。那該怎麼取得 error response 呢?axios 文件有寫了,用 err.response: https://github.com/axios/axios#handling-errors

axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      console.log(error.response.data);    // 取得內容,用 error.response.data
      console.log(error.response.status);  // 取得狀態碼,用 error.response.status
      console.log(error.response.headers); // 取得表頭,用 error.response.headers
    } else if (error.request) {
      // The request was made but no response was received
      // `error.request` is an instance of XMLHttpRequest in the browser and an instance of
      // http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

電影流水帳(2020/03/01~2020/03/15)

https://www.flickr.com/photos/135504457@N06/28730311681
Cara Delevingne
  • Time Freak (IMDB, Wikipedia),台譯:時間怪客。
  • Valérian et la Cité des mille planètes (IMDB, Wikipedia),台譯:星際特工瓦雷諾:千星之城。

Time Freak

Time Freak 故事蠻有趣的,是講男主角 Stillman 為了追求女主角 Debbie 製作了時光機器,然後試了無數次才成功的跟 Debbie 結婚,可是到了後來卻發現Debbie 沒有了熱情,他認為也許是自己扼殺了 Debbie 的熱情,為了讓心愛的人能更開心的生活,就決定回到過去讓自己無法製造這機器。跟著 Stillman 一起改變歷史的好友 Evan ,也跟著 Stillman 一起回到過去,已經享受過時光機器紅利的 Evan 試著阻止 Stillman 。但沒辦法阻止,Evan 只能眼睜睜看著 Stillman 無法發明時光機器了嗎?可是想不到,這時候 Debbie 赫然出現,知道真相的她相當的生氣,也透過時光機器回到過去,她很明白的告知 Stillman ,你不能這樣地隨意的操弄我的人生,把話說開以後,Debbie 跟 Stillman 相擁而吻,結束這故事。

Valérian et la Cité des mille planètes

盧貝松拍的,整個電影很有「第五元素」的既視感。基本上我蠻喜歡這故事的,有娛樂性,故事也有意思,只是後面有點拖戲了,沒有「第五元素」來的緊湊,蠻可惜的。除了故事以外,我也很喜歡女主角 Cara Delevingne ,她有點 Eva Green 的氣質,有點壞壞的,又很有魅力。

特工 Valerian 愛上女搭檔 Laureline,跟他告白,想說出完這次任務就結婚,一同去度假。想不到這次任務卻是意外的驚險,兩人歷經千辛萬苦,好不容易才取得神獸。回到星際城市阿爾法以後,本以為可以去結婚度假了,阿爾法有了狀況。這暫且按下不表,先說說阿爾法,阿爾法是個巨大的星際城市,裡面有各種不同的地形、環境,也有各種不同的人種,是個相當特殊的城市,這個城市由不同人種組成的政府來管理。那阿爾法出現什麼狀況了呢?在城市的某個角落沒有了通訊,也無法控制,派軍隊去了幾次,但都沒有人能回來。指揮官為了這事情傷透腦筋,開會討論,回來以後的 Valerian 跟 Laureline 奉命保護指揮官。會議才開到一半,就被人襲擊,指揮官被擄走。追蹤了訊號,發現訊號是消失在之前那個沒通訊的角落,Valerian 就開著飛艇到那邊去了。只是這次 Valerian 任務並不順利,Valerian 的飛艇被擊落,留守總部的 Laureline 為了救 Valerian ,違抗總部命令,隻身前往救援。

Laureline 透過關係,通靈到 Valerian 墜落的位置,然後前往那邊救出 Valerian。救出以後,他們決定更深入去尋找指揮官,卻也因此陷入了更多事件裡。不過在追查的過程裡,他們慢慢發現事情不簡單,指揮官這個人的意圖也不簡單,在總部代理指揮官也發現了這事情。追查到最後,他們終於把事情弄清楚,指揮官在數年前在打仗時,打算發射毀滅性武器幹掉敵人,敵人在某個星球附近,指揮官想說星球上應該沒人,也疏於調查,就決定發射了飛彈。敵人被滅掉了,而那星球上的種族也被滅了一大部分,殘存的人慢慢的學習科技,並逃到了阿爾法,並在裡面的某個角落生活下來,這個時間點也正好是阿爾法總部無法掌握那個角落的時間。後來指揮官知道了這事情,就想要把他們都滅了,永絕後患。總之,Valerian 跟 Laureline 透過該族的人了解了整件事情的前因後果,阻止了指揮官,揭發了他過去的罪行,該族的人民回歸和平,Valerian 跟 Laureline 結婚去了。

用 snap 跑 Folding@Home

環境:Ubuntu 18.04

這是看到 分享:處理 COVID19 之軟體專案數則 ,裏面提到 Folding@Home 可以幫忙運算與武漢病毒相關資訊,所以想裝起來幫忙。官方網站有提供 Linux / Windows / MacOS 的軟體,基本上裝起來就可以了。T客邦有篇介紹文章:

我不想裝 Debian package,想用 snap 來安裝,網路上有好心人打包好了。

安裝步驟很簡單,因為 Ubuntu 18.04 已經預先裝了 snap,接著只要用 snap 來安裝就可以:

sudo snap install folding-at-home-fcole90 --edge # 安裝
snap connect folding-at-home-fcole90:hardware-observe # 允許檢查硬體 (這是為了檢查 GPU 用,可以用 GPU 輔助運算)
snap services folding-at-home-fcole90.FAHClient # 檢查服務是否運行。

安裝好以後,在選單可以找到 FAHControl,執行它。第一步是先設定,按下工具列的 Configure,在 Identity 填入名字,以及 Team number。名字可以自己取,Team number 的話,請填 31403 ,這是台灣隊的編號,說明可以參考這篇 Folding@Home Taiwan Team。設定好之後,按下 “Fold” ,就會開始下載資料並進行運算了。以我的電腦配備,一個回合大約要兩小時。我有看到可以用 GPU 加速,我就依照這篇 How to Check Which GPU Is Installed on Linux 查了一下,看我的電腦有沒有支援 GPU,看了以後,我覺得應該是有,但 FAHControl 卻說沒有 (切到 System log 可以看到),查了半天都沒查出原因,後來才在 fah-snap 的 issues 看到這條 FAHClient cannot detect OpenCL correctly 。嗯,那看來只能等作者解決了,或者,裝 Debian package 試試看囉。

讓 docker daemon可以給別台電腦存取

docker 官方並不建議使用這方法,但還是有文件:Configure where the docker daemon listens for connections

不建議的原因很簡單,安全性。docker daemon 是用 root 權限在執行,而 docker 又沒有這方面的安全機制去處理帳號驗證,自然不建議這樣使用。 目前的主流是使用 kubernetes,另外,docker 最新的版本是有提出 docker context,利用 context 可以管理多種連接方式,其中一種連線方式是走 ssh ,會比較安全。

目前我只是想方便的操作虛擬機,所以可以不需要太考慮安全性問題。

編輯 systemd unit:sudo systemctl edit docker.service,把下面幾行貼進去

[Service] 
ExecStart= 
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375 

讓 systemd 重新載入設定: sudo systemctl daemon-reload

重啟動: sudo systemctl restart docker

檢查: sudo netstat -lntp | grep dockerd

在別台電腦上,先設置環境變數:export DOCKER_HOST=tcp://your_docker_host:2375 , 然後用 docker 指令就可以存取該台 docker 主機了。

用 redoc 來顯示OpenAPI規格文件

之前有找過怎樣輸出 OpenAPI 規格為文件,有試過 swagger-codegen 先轉成 HTML 再轉 PDF,但其實效果不好,也一直沒找到滿意的。

今天再來找一次,找到 redoc,依照 github 網站上的說明來作,用 redoc 提供的 docker image 就可以跑起 API 文件的 Live 網站,效果挺好的。

docker run -p 8081:80 --rm -v $(pwd)/api.yml:/usr/share/nginx/html/api.yml -e SPEC_URL=api.yml redocly/redoc

網站上還有提到一個 redoc-cli,說明說可以 bundle 成一個靜態HTML文件。有 homebrew ,就想說 homebrew 會不會有這個 formula,找了以後,發現是沒有,只好認命的用 npm 來裝

npm install npx npm install redoc-cli 

裝 npx 是為了可以方便的呼叫 node module 裡的指令來用,這部份的使用說明可以參考這篇:Introducing npx: an npm package runner 。 裝好以後,就可以使用了:

npx redoc-cli bundle api.yml 

輸出的檔案固定是 redoc-static.html,用瀏覽器開啟就可以了。

筆記:Queries, Part 1: Common SQL Queries Converted for Firebase

依照 Queries, Part 1: Common SQL Queries Converted for Firebase 來練習

  • By ID ,路徑指定好就可以了 firebase.database().ref(‘/messages/’ + messageID).once(‘value’, function(snap) { … });
  • WHERE, 除了路徑之外,還要指定 orderByKey() 或 orderByChild(),然後再用 startAt/endAt
    • orderByKey 是依照 key 的值:firebase.database().ref(‘/messages’).orderByKey().startAt(‘user001’).endAt(‘user010’).once(‘value’, function(snap) { … });
    • orderByChild 是依照子節點的值:firebase.database().ref(‘/messages’).orderByChild(’email’).startAt(‘user001@example.com’).endAt(‘user010@example.com’).once(‘value’, function(snap) {…});
    • 用 orderByChild 時,要在規則裡加上 .indexOn ,否則會有警告,警告的大意是說加indexOn 後,效能會比較好。
  • LIMIT,加 limitToFirst(10) 或 limitToLast(10)
    • 可以跟前面提到的 startAt / endAt 結合:firebase.database().ref(‘/messages’).orderByChild(’email’).startAt(‘user001@example.com‘).endAt(‘user010@example.com‘).limitToFirst(10).once(‘value’, function(snap) {…});
    • limitToLast 就是指定後面幾筆

筆記:firebase functions – realtime database

閱讀的文件:https://firebase.google.com/docs/functions/database-events

可以寫這些事件的處理常式

  • onWrite() 資料被建立、更新或刪除時,會觸發
  • onCreate() 資料被建立時,會觸發
  • onUpdate() 資料被更新時,會觸發
  • onDelete() 資料被刪除時,會觸發

可以只針對指定的路徑,對,也因為事件資料同時包含舊的跟新的,資料量有限制,資料量大的時候要針對個別路徑拆開來寫處理常式。

可以用參數,例如 ref(‘foo/{bar}’)  ,那麼存取 foo/hello 或 foo/firebase 時,都會觸發常式對 foo/ 寫入,像下面

{
  "foo": {
    "hello": "world",
    "firebase": "functions"
  }
}

會觸發兩次常式,一次是 foo/hello ,一次是 foo/firebase從 EventContext.params 可以用 bar 這個 key 去拿到 hello 或 firebase
範例

 
// 當有訊息加到 /messages/:pushId/original 時,執行這常式。 
// 這常式會把指定路徑下的值,轉為大寫,再放到 /messages/:pushId/uppercase 
exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') 
    .onCreate((snapshot, context) => {  // snapshot 是 DataSnapshot ,context 是 EventContext 
      // 先取得寫入的值 
      const original = snapshot.val(); 
      console.log('Uppercasing', context.params.pushId, original); 
      const uppercase = original.toUpperCase(); 
      // 把資料寫到 "uppercase" sibling 然後回傳 Promise 
      // snapshot.ref.parent -> /messages/:pushId 
      // snapshot.ref.parent.child('uppercase') -> /messages/:pushId/uppercase 
      return snapshot.ref.parent.child('uppercase').set(uppercase); 
    }); 

用 EventContext 的 auth / authType 就可以取得 authentication 資訊 (這邊我有點迷糊了,為啥 authType 可以是 ADMIN / USER ??

onWrite 的時候,是用 change, context change 是 Change,提供了 before/after property 可以存取寫之前/之後的值 。

筆記:以適合的 HTML 屬性增強輸入 2FA 的體驗

來源:HTML attributes to improve your users’ two factor authentication experience

TL;DR

  1. type 維持在 text
  2. inputmode 改為 numeric,這樣可以在手機平台上出現數字鍵盤,而不是完整的鍵盤
  3. pattern 設為 [0-9]* ,可以確保輸入的文字是數字
  4. autocomplete 設為 one-time-code ,是可以確定自動完成的部份是「一次性的密碼」,之前以為只有 “off” ,其他可以用的數值可以參考這篇
<input
  type="text"
  name="token"
  id="token"
  inputmode="numeric"
  pattern="[0-9]*"
  autocomplete="one-time-code"
/>