2021/09/16

Just a Note: Install Podman in WSL2

當初是因為 docker desktop 要開始收費,所以進行了很初期的 survey,不管是 docker 還是 podman,基本上在 windows 上不外乎就是透過 virtualbox/wsl 載入能執行 docker/podman 的 linux 系統,對於不熟 linux 的人(像我),程序難免複雜。
而這一年來,使用過 rancher-desktop、podman、minikube,在 windows 上的發展也都相當健全,我認為也都很容易便可當作 windows 上容器化技術的開發工具,不需要像初期一樣大費周章了。
rancher-desktop:https://rancherdesktop.io/
podman:https://podman.io/
minikube:https://minikube.sigs.k8s.io/

rancher-desktop、podman 會使用 wsl,minikube 則可以選擇 virtualbox 或 hyper-v 作為 hypervisor,有點像早期的 docker-toolbox。
我個人比較偏好使用 wsl 的 rancher-desktop、podman,主要是因為當要使用 container volumn 時,多透過一層 hypervisor 在設定上比較繁瑣,先前用 virtualbox 時,這部分常踩到雷。
rancher-desktop 可選擇 containerd 或 docker 作為 container runtime,對於原本習慣用 docker 的人應該會比較熟悉,在家試一些新東西時,主要都是使用 rancher-desktop;
podman 初期接觸的契機是因為工作,Red Hat 在 OpenShift 上主推的 container runtime 就是 podman,後來也因為 k8s 對於 docker 的支援上存在一些爭議與討論,所以工作上主要就都改用 podman,雖然還是只用在類比 docker command 上就是了。現在新的版本已經直接支援 docker api (模擬),也就是說安裝了 podman for windows 後,可以直接使用 docker 指令,但畢竟不是原生 docker,應該還是會有一些出入吧;
至於 minikube,是公司的分享會介紹的,只有簡單使用過,但因為會產生 virtualbox 或 hyper-v 的 vm,有些資安議題上的爭議,再加上前面提到的 volume 議題,所以我個人就不太偏好了,不過畢竟是公司在推廣的工具,所以還是加減看看。

近幾年容器化技術發展快速,無論使用哪套工具,在 windows 上皆已相當方便,原本複雜程序的文字就還是留著作為歷史紀錄吧!

2022.09.10 中秋

2016/10/11

Just a Note:Use GIT as SVN Client

2016.10.03 補充:
略過不要 fetch 的目錄。

當團隊中有人使用非 Windows 系統時,可能會發生 svn 中出現 Windows 無法接受的字元的目錄,
即使事後刪除了,但這樣的資訊仍會存在 history 中。

若此時使用 git svn 進行 fetch,便會發生無法建立目錄的錯誤。
此時可以透過 sparse checkout 避開這樣的目錄,具體步驟如下:

1. git config core.sparseCheckout true
2. 查看 .git/info 目錄下是否有 sparse-checkout 檔案,若無,新增一個。
3. 在檔案中加入
/*
!不要的目錄路徑

4. 重新執行 git svn rebase 或 git svn fetch

5. 即使加了上述的設定,在 git svn rebase 時,還是會有問題,此時就必須額外加上 --ignore-paths 忽略有問題的路徑:
git svn clone some_svn_url . -s --prefix=svn/ --ignore-paths="^(?:trunk|branches|tags)/不要的路徑"
git svn rebase --ignore-paths="^(?:trunk|branches|tags)/不要的路徑"


沒想到已經三年沒寫筆記了......

2016/04/07

Just a Note:Git Submodule

紀錄 git submodule 多人共用的情境與步驟。

1. 第一個新增 submodule 的人
git submodule add -b [submodule_branch] [submodule_url] [submodule_folder] (submodule_folder 需不存在,會產生或更新 .gitmodules)
git submodule init (register submodule in git)
git submodule update (把 submodule 的檔案更新回來)
git add .
git commit -m "add submodule"
git push

2. 其他人
git pull (submodule 目錄會是空的)
git submodule init (register submodule in git)
git submodule update (把 submodule 的檔案更新回來)

3. 更新 submodule:
(1) 在 submodule 原始的 repository (不是在此系統的 repo 下)修改,按照標準 git 程序進行更新。
(2) 直接在此系統的 submodule 目錄下進行修改:
cd [submodule_folder]
git add [stuff]
git commit -m "[comment]"
git push origin HEAD:[submodule_branch]

4. submodule 有更新,第一個處理 submodule 更新的人
git submodule update --remote (更新 submodule 檔案及 local git 紀錄的 submodule hash)
git add .
git commit -m "submodule update"
git push (如此 remote server 的 submodule reference 才會更新,否則其他人都還是會用到舊版的 submodule)

5. 其他人
git pull
git submodule update


參考:
Git submodules: Specify a branch/tag
http://stackoverflow.com/questions/1777854/git-submodules-specify-a-branch-tag
Git Submodule 的認識與正確使用!
http://josephjiang.com/entry.php?id=342
Issue with adding common code as git submodule: “already exists in the index”
http://stackoverflow.com/questions/12898278/issue-with-adding-common-code-as-git-submodule-already-exists-in-the-index
How do I remove a Git submodule?
http://stackoverflow.com/questions/1260748/how-do-i-remove-a-git-submodule
git submodule update --remote vs git pull
http://stackoverflow.com/questions/19619747/git-submodule-update-remote-vs-git-pull
git-submodule(1) Manual Page
http://git-scm.com/docs/git-submodule

2015/11/22

Just a Note:Simple Git Server on Windows (Using git daemon)

As Server

f:
md reop
cd repo
git init --bare xxxx.git
git daemon --verbose --base-path=f:/repo --export-all --enable=receive-pack



  • --verbose:開啟詳細 log,加了之後除錯比較方便。
  • --base-path=f:/repo:告訴 deamon 你的 git repository 統一放在哪個目錄下,可以在此目錄下建立不同的 git repository。以上述的例子,就是 xxxx.git 的父目錄。
  • --export-all:允許 pull base path 下所有的 git repository
  • --enable=receive-pack:開放匿名存取,目前還沒研究怎麼在 git daemon 裡做 access control。

As Client

git config --global sendpack.sideband false

  • Client 要設定此參數,在 push 時才不會 hang 住。

git clone git://yourserver/xxxx.git

  • git://yourserver 便會指到 daemon 的 base path,後面的 xxxx.git 就是在 base path 下建立的 git repository。

2014/12/07

Just a Note: GCALDaemon 1.0 alpha 17 for Google Calendar API V3

Google 公告於 2014/11/17 停止支援 Calendar API v2,請使用 API v3。
As announced by Google, Google Calendar API v2 is a subject to the Deprecation Policy and was shut down on November 17, 2014. Please use APIv3 instead.

所以便試著將 GCALDaemon 提升至 API v3。
So I try to upgrade Google Calendar API to v3 for GCALDaemon.

我只有針對 Google Calendar 和 Rainlendar 同步處理的部分,修改了兩個功能:
1. config-editor 中的檔案同步設定。
2. sync-now (手動同步)
I only modified two function for synchronizing calendar events between Google Calendar & Rainlendar.
1. config-editor for File synchronizer.
2. sync-now (manually sync)

修改後的程式可以在 github 取得。
The modified source can be download from github.

在 API v3 中,有兩項比較顯著的變更:
1. 授權方式:必須使用 OAuth 2.0,而不支援其他的授權方式。
2. Google 日曆的 private URL:無法透過 API 取得 private URL 了。
For API v3, there are two significant changes:
1. authorize method: Application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
2. calendar private URL: We can't fetch calendar private URL from API anymore.

所以在開始使用新版 GCALDaemon 前,需要進行以下步驟。
So we have to follow steps below to use new GCALDaemon.

1. 從 My Google Drive 下載 GCALDaemon 並解壓縮。
1. Download GCALDaemon from My Google Drive and unzip.

2. 啟用 Google Calendar API。
2. Enable Google Calendar API.
(1) 開啟 Google Develop Console 並新增專案。
(1) Go to Google Develop Console and create a project.

(2) 啟用 Calendar API。
(2) Enable Calendar API.

(3) 新增 Client ID。
(3) Create Client ID.




(4) 下載 JSON,並更名為 client_secrets.json。
(4) Download JSON and rename to client_secrets.json.

(5) 將 client_secrets.json 放到 GCALDaemon/etc 目錄中。
(5) Put client_secrets.json into GCALDaemon/etc folder.

3. 執行 bin/config-editor-new.bat (或  bin/config-editor-new.sh),點選 "File synchronizer"。直接點選 "+New" 新增欲同步的日曆,不需要做 Account 的新增。
3. Execute bin/config-editor-new.bat (or bin/config-editor-new.sh) and click "File synchronizer", Just click "+New" to add Calendar you want to sync. Don't need to add Google Accounts.

4. 點選 "Refresh" 取得 Google Calendar 清單,此時會開啟瀏覽器,並要求授予管理日曆的權限。同意後,便可在下拉選單中看到你的日曆清單。
4. Click "Refresh" to fetch Google Calendar list from your default logged-in Google Account. There will show authorizing page in browser and you should click accept. Then you can get calendar list into combo box.



5. 選擇要同步的日曆,並指定對應的 iCal 檔案路徑。
5. Select the Calendar you want to sync and specify the iCal file location. Click OK.

6. 取得並複製該日曆的 ICAL 私人網址,只要保留 /calendar/ical/xxxxxxx/private-yyyyyyyy/basic.ics 的部分。
6. Open browser to get Google Calendar private URL. Copy the private address of ICAL and only keep the URL like /calendar/ical/xxxxxxx/private-yyyyyyyy/basic.ics

7. 回到 Config Editor 並修改步驟 5 新增的日曆,修改 Google Calendar 欄位,輸入步驟 6 取得的 URL。
7. Back to Config Editor and edit the calendar created on step 5. Change the Google Calender field to /calendar/ical/xxxxxxx/private-yyyyyyyy/basic.ics from step 6.


8. 儲存並離開 Config Edit。
8. Save and Exit config-editor.

9. 執行 bin/sync-now-new.bat (或 bin/sync-now-new.sh ) 進行同步。
9. Now you can execute bin/sync-now-new.bat (or bin/sync-now-new.sh ) to synchronize Google Calendar and the iCal file for Rainlendar.

2014/12/03

Just a Note:不常駐 GCALDaemon 又能自動同步 Google Calendar 和 Rainlendar 的方法

2014/11 Update:
Google 在 2014/11/17 停止對 Calendar API v2 的支援,所以 GCALDaemon 已經無法正確同步 Google Calendar 了。
所以在善心人士修正 GCALDaemon 前,也許只剩下購買 Rainlendar Pro 一途。
如果你真的還想要繼續用 GCALDaemon,可以參考這篇,但是說實話,程序複雜很多......


2014/09/11

Trip:東眼山國家森林遊樂區



中秋前一日,東眼山森林遊樂園。

約莫兩個小時的車程,初次拜訪東眼山。整個森林遊樂區腹地極廣,涵蓋了東眼山、親子峰兩處登山步道,以及較為緩和的東眼山林道、景觀步道、森林知性步道。
因為沒有事先做功課,所以一時間也不知道該怎麼走比較適當,所以便選擇先東眼山林道,打算抵達造林紀念石後,再看狀況評估後續路程。
整個林道起伏不大,但都是碎石路,且正午時分樹蔭又相對少了些,走來有些痛腳且悶熱,所以抵達化石區後便決定折返。
當下評估狀況,覺得不適宜再登高,所以決定捨棄親子峰和東眼山登山步道,計畫循森林知性步道+景觀步道前往餐廳、再到遊客中心。

從化石區折返後,選擇了過了景觀亭的第一個岔路離開林道。高聳參天的柳杉、原始潮濕的步道,景觀與林道迥異。
沿途全無人跡,所幸並無岔路,所以走來倒也輕鬆愉快,直到經過了往親子峰的登山口,遇到了第一批反方向來的遊客。
接著到了一個三岔路口,卻僅標示著親子峰的方向,本想詢問坐在路旁休息的一對男女,最後決定選擇往較多人過來的方向前進。

炙熱的陽光消失,且飄起了細雨。心想著趕快抵達餐廳避雨,順便看看有甚麼能填肚子的。
不知道何時一個著藍色衣服的小男孩超越我們,獨自一個人在步道中前進,且看來神色自若,我回頭望了望,不見其他大人的身影,暗忖著這小朋友怎麼這麼大膽在山中獨自一人,感覺就像他家後院一樣。
小男孩三步併兩步地前進,很快就遠離了我的視線,但過沒多久,便聽到遠處傳來哭聲,並清晰地喊著喊著「我要找爸爸、我爸爸不見了」。
我們加快了步伐,來到了一個四岔路口,看到小男孩蹲在路口不遠處、南面的步道上。正準備過去他身邊時,卻瞥見小男孩突然用餘光看向我們,然後又繼續哭喊著相同的字句。
心中升起一陣違和感,所以便停在路口,喊了他兩聲,小男孩沒搭理,逕自在步道上來回跑著、哭著。
正盤算著該怎麼處理、同時也在研究路線時,剛才坐在路旁休息的男女從後方出現,小男孩也看到他們,並開始往回走。
我以為那就是小男孩的爸媽,但很快便知道不是。小男孩依然哭喊著繞過我們走向那對男女,男的叫他牽著阿姨的手、又問了他一些問題,便說「我們帶你去餐廳,那裡有廣播」。
剛剛還哭天搶地的男孩突然就噤聲乖乖地跟著他們走,而男女也毫不遲疑地往某條草高及腰的岔路前進。

我還在研究該怎麼走。
他們也要去餐廳?跟他們走就好了?看看指標,四岔路只有三個指標,餐廳的指標卻指向兩條岔路的中間?再看看路線示意圖,他們走的方向似乎是往林道的方向?
雖然有很多問號在腦中浮現,但想了想,還是決定按照自己的方向感前進,沿途看到更多的遊客迎面而來,讓我更加確定自己沒走錯。

那對男女和小男孩呢?
抵達餐廳後,稍做等候,並未看見三人,而沿途也沒看到像是在找尋小孩的家長,更不用說一直到離開園區為止,根本沒有聽到任何廣播。
抱著很多疑問離開園區,突然大雨滂沱,躲進了布列塔尼咖啡莊園等雨停,然而沒花費什麼體力且悠閒地享用過咖啡的我,卻在回程時疲憊到不得不停下車在路邊休息後才能再繼續騎車。

我們心中都有許多疑惑,但直到隔天晚上才拿出來討論。
小男孩甚麼時候出現的?我們走的路一直沒岔路,後方也都沒人,遇到的第一批人是和我們反方向的。
原本神色自若、步伐輕快的小男孩,怎麼突然就在路邊放聲大哭?
哭的時候咬字怎麼還能那麼清楚?
「我要找爸爸、我爸爸不見了」,感覺就是要喊給路人聽的......
那對男女走的路線,顯然不是往餐廳的路(雖然可以到,但是比較繞)。

當你想著這小孩怎麼沒人陪,就突然聽到他的哭喊,雖然前一刻他還神色自若......
當你在岔路研究要怎麼到餐廳,突然有人也說要去餐廳,毫不遲疑地就走向其中一條岔路,但卻是方向錯誤且沒有指標的那條......

2014/07/21

Just a Note:Jetty Runner

說明:
Jetty/Howto/Using Jetty Runner

下載:
Jetty Runner Download

看起來只有 for Jetty 7.x 和 8.x 的版本,不過應該已經足夠。

基本的需求是:
1. 把 Web Application 當作 stand alone 的應用程式部署。
2. 檔案愈少愈好。

如此便只需要 jetty runner 的 jar 檔和 application 的 war 檔共兩個檔案,透過 command line 便可以啟動 application,如此對 Application Server 的依賴度就會降低。

啟動程式:

java -jar jetty-runner.jar --path /myapp myapp.war

2014/07/17

Why Do I Choose Redmine for Issue Tracking?

必須先說明,工作以來用過 Mantis、Clear Case、Trac、Redmine 等 Issue Tracking System,Clear Case 要商用軟體就不用談了,真正有實際架設經驗的只有 Trac 和 Redmine,會選用 Redmine 作為主要 Issue Tracking 系統的原因如下,主要還是跟 Trac 進行比較:

1. 原生支援整合 Subversion、Git。
 這段分析對 Trac 比較不公平一些,之前使用 Trac 時,經歷了整合 Subversion 1.4.x、1.5.x、1.6.x 和 Git,每一階段都很痛苦,因為 python 的版本、Trac 版本、相關 plugin 版本的配合著實令人頭痛。後來改用 Redmine 時,Subversion Server 已經固定使用 1.6.x 版,所以只要選用支援的版本,基本上就可以無痛整合;另外隨著 Git 的普及,原生整合 Git 對我來說也是相當重要的功能。我之前同時嘗試用 Trac 和 Redmine 整合 Git,但最後 Trac 沒有試成功,而 Redmine 則是無痛整合。

2. 較完整的使用者/權限管理/設定,使用者亦可自行進行密碼變更。
 之前用 Trac,沒有使用者自行管理密碼的功能(可能需要額外安裝 plugin),使用者的密碼都是管理者設定後便固定不變,其實這樣有點怪。

3. 較完整的專案管理/設定
 原生支援 multiple projects、子專案,透過 Web 管理介面便可進行專案的建立與設定。Trac 則是需要先建立一個 template,每要開一個新的專案,就需要複製實體目錄,再手動進行 config 的修改,操作門檻較高,且基本上 Trac 各專案均為獨立個體,只能透過 Web Server 設定,「假裝」有一個統一的入口。

4. 原生支援 wiki/論壇/行事曆功能
 Trac 原生只有 wiki,論壇、行事曆均需額外安裝 plugin。真的經歷過安裝 Trac plugin 的痛苦,便能體會原生支援的美好。

5. Email 通知功能
 Redmine 原生支援。Trac 大概也是得安裝 plugin 吧......

6. 外部系統可整合 Redmine 的使用者,達到 Single Sign-On 的目的。
 目前已將 Subversion、Git、Jenkins 的登入統一由 Redmine 控管。



當然我的需求和考量的點不見得對每個專案與環境都適用,僅供大家參考。

網路上都說 Trac 架設的門檻高,根據經驗的確如此,當要使用其他 plugin 時,更是痛苦。不過嚴格說起來,其實 Redmine 的架設也不是真的很容易,要感謝 Bitnami 提供相當完整的 Installer,讓這些系統的架設變得更為容易。

2014/06/14

MOOC

最近開始接觸 MOOC(Massive Open Online Course,大規模網路免費公開課程),網路上有很多介紹的文章,我不敢說對每個人都會有顯著的效益,但這就跟在求學的時候一樣,每個人都上了很多課,但不見得獲得了相同的知識,所以還是蠻建議有興趣的人可以研究看看。
我目前只接觸了 Codecademy 和 Coursera,Codecademy 是屬於程式設計的課程,因為是本業,所以想借此看看現在的趨勢;Coursera 的領域則非常廣泛,感覺就很像大學的通識課。由於我只各參與了一門課(還沒修完),所以沒辦法進行評價,但可以分享一下初步接觸 Coursera 的感想。

1. 大多數都是英文課程,透過影片進行授課,影片可以開啟字幕、可以調整速度、可以隨時暫停,所以對於想提升英文能力的人,我相信一定有幫助。
2. 如果是想快速了解課程的內容,影片幾乎都有簡體中文、甚至正體中文的字幕,相信可以提升學習的效率。
3. 很多已經結束的課程都開放隨時選修,只是就不清楚是不是還有做業、考試的互動了。
4. 課程會區分成許多段最多數十分鐘的影片,每週時數加總起來大概也不會超過兩小時,所以如果加上練英聽、做作業,粗估每週花費 12 ~ 24 小時應該就可以完成該週的進度。
5. Android 和 iOS 上都有 Coursera 的 App,影片都可以下載到手機或平板上,可以利用零碎的時間反覆觀看。

附上一些介紹 MOOC 的連結,提供給大家做參考:
http://www.thenewslens.com/post/45399/
http://www.thenewslens.com/post/36571/
http://www.inside.com.tw/2014/06/13/a-taiwanese-developer-thought-about-coursera

2014/06/11

Just a Note:StandardPasswordEncoder 解析

StandardPasswordEncoder 是 Spring Security 提供的 class,僅有兩個 method:encode 和 matches,分別用來對密碼進行編碼及驗證。

StandardPasswordEncoder(CharSequence secret)
String encode(CharSequence rawPassword)
boolean matches(CharSequence rawPassword,String encodedPassword)

編碼的演算法基本上為 Hash,但並非單純的 Hash,其因子有三:
1. Secret:透過 Constructor 傳入,用來和 Raw Password 一起進行 Hash 的資料,通常為有意義的唯一值,例如帳號,以避免不同帳號、相同密碼產生出一模一樣的 Hash 值。
2. Raw Password:密碼明碼。
3. Salt:為一亂數,用來強化密碼編碼。

編碼的基本流程:
0. 使用者註冊時,輸入帳號、密碼。
1. 根據帳號 (Secret) new 出一個 StandardPasswordEncoder 物件。
2. 呼叫 encode,傳入密碼 (Raw Password)。
 (1) 產生 n byte 的 Salt。StandardPasswordEncoder 中會產生 8 bytes 的亂數。同一系統中,Salt 的長度需相同,除非連長度都當作產生 Hash 的因子保存下來。
 (2) 將 (1) 產生的 Salt、1. 傳入的 Secret、2. 傳入的 Raw Password 組合起來一起進行 Hash 運算,產生 Hash。StandardPasswordEncoder 採用 SHA-256 演算法,並針對資料進行 1024 次 Hash 運算。
 (3) 取得 Salt+ Hash (Encoded Password),存入資料庫。

步驟 2. (1) 加入了未知長度、且每次隨機產生的 Salt,即使使用相同帳號 (Secret)、相同密碼 (Raw Password),每次編碼出來的結果也不會相同;
步驟 2. (2) 進行了多次 Hash 演算,最後的結果就不會是以單純的 ASCII 字元產生出的 Hash,而是值域更廣 binary data,可以增加暴力破解的難度。

驗證的基本流程:
0. 使用者登入時,輸入帳號、密碼。
1. 根據帳號 (Secret) new 出一個 StandardPasswordEncoder 物件。
2. 呼叫 matches,傳入密碼 (Raw Password) 和從資料庫取得的 Encoded Password。
 (1) 從 Encoded Password 中取出 Salt 和 Hash。
 (2) 將 (1) 取得的 Salt、1. 傳入的 Secret、2. 傳入的 Raw Password 組合起來一起進行 Hash 運算,產生 Hash'。
 (3) 比對 (2) 產生的 Hash' 和 (1) 取得的 Hash 是否相等。相等則代表密碼驗證成功。


原則上透過 StandardPasswordEncoder 的 encode 出來的結果已經很難透過暴力破解取得使用者密碼了,不過也可以再進一步調整部分編碼的參數,例如:
1. Salt 的長度。
2. Hash 時 Salt、Secret、Raw Password 排列組合。
3. Hash 的演算法和次數。
4. Salt、Hash 的排列組合。
只要在 encode 和 matches 中使用相同的因子,便可以自訂出獨有的密碼編碼機制來強化密碼的保護。

如此一來,即便有內部人員可以直接存取資料庫,也無法取得使用者的密碼。

2014/06/05

詐騙簡訊...

友人分享了一個詐騙簡訊,簡訊說「這是上次聚會的照片」,還附上了一個短網址。

短網址還原後,是個韓國的 IP,話說上次也是韓國的 IP,不知道是不是這個空間比較好租......

網址是個 php,但是居然可以瀏覽目錄(也太不專業了)。
目錄底下有兩個 php、一個 txt、一個 jpg、一個 apk( 一.一+ )。

php 沒辦法下載,會自動 rediret 去下載 apk 檔;
jpg 其實是個 xuite 的網頁,是個聚會的照片,跟簡訊描述一致,所以其實不算詐騙?(是這樣解釋的嗎?)
txt 是 log 檔,記錄了所有點擊簡訊內連結的裝置資訊,例如手機型號、OS版本、瀏覽器版本、IP、點擊的時間等等。附帶一提,這個 log 檔有 203 MB,包含 5/21 到今天的點擊資訊,總共有 63 萬筆......也就是每天有 4 萬多次點擊,其中有非常多人是一而再、再而三地點、不停地點......

apk 是重頭戲啦!馬上拿去反組譯,看看到底寫了甚麼神奇的功能,可以達到詐騙的目的。
基本上是一個在 Android 上可以跟遠端溝通的常駐程式,主要功能如下:
1. 取得此裝置通訊錄。
2. 遠端可偵測此裝置是否上線。
3. 取得此裝置所有收到的簡訊。(重點!)
4. 上傳所有目前裝置內的簡訊。
5. 透過此裝置發簡訊。

所以當使用者點擊了詐騙簡訊的連結、也安裝了 apk 後,這時候小額付款機制就派上用場了......
詐騙集團使用安裝木馬的手機號碼進行小額付費,小額付費會發認證簡訊到該手機上,因為上述 3 的功能,詐騙集團可以立刻拿到授權碼(根本不需要用 line 跟你裝熟、請你幫忙收簡訊......),其實現實中還有很多使用簡訊 OTP 進行認證授權的機制,這時候都變成詐騙集團可以利用的管道。
然後你的荷包就被掏空了......

報告完畢,謝謝收看。

2014/04/13

Android App:Daily Money New Branch for DB Schema Compatibility

This project is a fork of original Daily Money project hosted on github by Dennis Chen

https://github.com/dennischen/daily-money

建立新的分支,在不改變官方資料結構的情況下加入新功能。
所以此分支不包含
1. 金額由 double 轉 BigDecimal 的處理。
2. Tag 功能。

APK can be downloaded in dist folder.


完整功能版本:
Source & Binary:
https://github.com/LancelotLiu/daily-money-1/tree/lancelot
APK can be downloaded in dist folder.

2014/03/07

Just a Note:Sun JCE 驗章問題

驗章時須使用 Public Key,一般來說,在 JCE 下使用已知的 Key 值建立 Public Key 的方式有兩種:

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pubKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);

RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);

差別在於 Key 值的保存型態,
第一種存的是 Key.getEncoded() 的值 (http://docs.oracle.com/javase/7/docs/api/java/security/Key.html),
第二種保存的是 Public Key 的 modulus 和 exponent。而使用第二種方式時,通常我們亦會把 modulus 和 exponent 用 byte[] 保存。

最近遇到的問題是,
如果 Public Key 是透過 RSAPublicKeySpec 建立的話,會驗章失敗;使用 X509EncodedKeySpec 建立的話,則會成功。
但是把兩種方式建出來的 Public Key dump 出來 (getEncoded()),卻會得到一模一樣的值。

Debug 後發現,
RSAPublicKeySpec 建出來的 Key,其 modulus 是負數,
X509EncodedKeySpec 建出來的 Key,其 modulus 則是正數。

解決方式:
當 modulus 的第一個 byte 大於等於 0x80 時,需在最前面多放一個 byte 0x00,再轉成 BigInteger,即能正確取得 modulus 的值。

String modulusStr = "C868EEE8D1D300207EA65DB1DBBFD52552AE1814E07FDF23DE040EC96E6F0F35C8ECF922C11D7F39B3E3162B96881447D16B0FCC75FB0378F2B19AFB22884B8F2E2840C74FE73DBCDBF653E26070955BB9A4011C1EDD9E1DBA482F02091DBBFAD77D13F91A06FF76C8FDE1E4F475A2DFF8A9567C115F50ACCA573315F7723D333218E266984953D0642057C46D6F952CFC7CFAEAA8945FAEDE441ADA8497F0895C1AC18CE6679467F6EFEF5C741879487E94B8DAF87FA45E87FD011BB0A794B4F433B655959B6D1D8164793421A360A39E17A2287EE5CFE7200FF6FA3F407DD7FEC2EAA6C6A89BE5A3CE3073B758E56654C17CE17A3657E76E219E1BECA9115D";
byte[] modulusTmp = Util.hexStringToByte(modulusStr);
byte[] modulus = null;
if (modulusTmp[0] < 0) {
    modulus = new byte[modulusTmp.length + 1];
    modulus[0] = 0x00;
    System.arraycopy(modulusTmp, 0, modulus, 1, modulusTmp.length);
} else {
    modulus = new byte[modulusTmp.length];
    System.arraycopy(modulusTmp, 0, modulus, 0, modulusTmp.length);
}

2014/01/05

Android App:Daily Money Change Log 2014/01/05

This project is a fork of original Daily Money project hosted on github by Dennis Chen

https://github.com/dennischen/daily-money

added: hide accounts with zero balances in reports

新增:在報表隱藏金額為零的帳戶

(顯示)

(隱藏)


2013/05/14

Android App:Daily Money Change Log 2013/05/14

This project is a fork of original Daily Money project hosted on github by Dennis Chen

https://github.com/dennischen/daily-money

added: search details by date and note

新增:根據日期及備註搜尋帳務明細






2013/04/23

Those Days in DES Team


整理硬碟,看到自己過去做的案子、寫的 code,想起自己在 DES Team 的日子。

Genkey 程式
到公司半年後的 2003/3~2004/8 一年半間密集地做了五家銀行主機安控提升案的 Genkey 程式和部分的主機 SUIP 外加一個 Open 端安控系統的功能新增。剛開始甚麼都不懂,只會拿前人已經寫好的程式,複製、修改、測試,過了就當作 OK。

就這樣做了三個專案,上百個 java Panel (12+74+65),常常遇到改個字、調個位置就要同時修改數十支 java 檔。
後面兩個專案因為前面的痛苦經驗+客戶要求,所以把數十個 Panel 彙整成八個,然後另外寫了一個工具產生選單和設定檔,不用一分鐘,就可以完成原本一個 Panel 要做的事情。如果畫面有需要微調的部分,最多也就是改 8 支程式。對比前面三個專案,如果要全部重做,開發的時間大概可以從數週縮短為兩天。
之後又花了一些時間把 Genkey 和工具加以改良,可以同時支援檔案匯出(for 主機安控)和 IC 卡儲存(for Open 安控)。

對 2004 年那個甚麼都還不會的我來說,其實很有成就感,即使現在看來那些 code 寫得一蹋糊塗,但至少縮短了大量瑣碎工作的時間。

只是有趣的是,做完這些之後,我就被派去支援端末,開始游牧民族般的專案生活,再也沒有碰過主機安控系統的開發。所以寫好的工具和程式就跟垃圾一樣一直躺在 file server 和我的硬碟裡,也沒有機會在任何專案中驗證。大概也沒人知道那套程式可以支援 IC 卡儲存。

PS. 後續有兩三個主機提升案曾拿去使用,但據我所知都是加上 Panel 複製、修改的混合體了。

留職停薪
2005/6,在支援端末又被調回後,決定留職停薪。會這麼做要感謝兩個貴人,因為他們很樂於分享,但是很多名詞我都聽不懂,即使是一些很基本的 java 概念。
美其名寫了 3 年的 java,其實當時我連 extends 和 implements 都搞不懂,也不知道甚麼是 abstract class 和 interface,別人明明寫好的 i18n 程式被自己改成 hard code 文字還感到很得意可以省下 native2ascii 的時間。
所以我決定留停 K 書考認證。原本計畫要考 SCJP 和 SCWCD,但惰性比自己預期得來的強大,所以最後草草 K 了 3 週、趕在 voucher 過期前去考了 SCJP,超低空飛過。
2005/10,WOW 開始公測,嗯...就不用多說甚麼了...

Security Server
2006/4,留職停薪後第一個正式參與的專案。
第一次從無到有寫 socket server、multi-thread、JCE 程式。其實一度因為寫不出來想放棄,所幸後來有把程式生出來交差......依然要感謝相同的兩個貴人,一個提供我很多建議、一個提供我範例程式且適當地回絕了我的推託。
接著又陸續調整,用在其他四、五個專案,相同的架構、介接不同的 HSM。
但因為工作分派的關係,幾乎都交接出去。
可能是我程式寫得很爛吧!即使花了很多時間做交接,感覺也沒人真的去了解我的想法、說了甚麼、寫了甚麼,得不到任何反饋。唯一的反饋當時覺得很刺耳,但的確也是我到現在都還不足之處。

不管是 Genkey 還是 SS,即使到現在,我都一直還覺得有很多地方可以改進、需要改善。
但說真的,想歸想,真的一點動力都沒有。反正大部分的人都覺得能跑就好了。



DES 的專案其實很有趣,完全就是看客戶環境決定你需要在甚麼平台、用甚麼程式語言寫程式。在留停之前的短短三年內,我寫過 COBOL、Java、C/C++、VB、ASP,碰過的作業系統有 OS2、Windows、RedHat、FreeBSD、CICS、IMS、AIX、AS400,雖然沒有任何一項能搬上檯面,但是在這些專案中,我想我大概理解了 SI 的意義。
時至今日,大環境並未改變,甚至更為複雜,我想,大概永遠只能當隻鼯鼠。


2013/04/05

Candy Crush


Candy Crush 最近火紅,在 FB 上連很多早就宣告不玩遊戲、不接收遊戲 request 的朋友都淪陷了。
我也不例外,完成 170 關,不過距離目前開放的 355 關,連一半都還不到。

心得:
1. 基本上這是個很吃運氣的遊戲,愈後面的關卡愈是如此。
2. 遊戲支援 Android、iOS、FB,每個裝置的「愛心」數量是獨立的、而完成的關卡在與 FB 連結後是同步的,所以像我有兩台 Android 裝置加 FB,每次玩就基本有 15 次機會。
3. 第一個連結 FB 的裝置,只要不確認,就可以保留所有 FB 好友送愛心的訊息。但如果是用 FB 開啟遊戲,所有訊息中的愛心或物品都會直接視為已接收,無論你有沒有按確認。
4. 基於 2, 3 兩點,到後來除非連玩好幾小時,不然其實很難把愛心用完。

不過決定要戒了,
我想最簡單的戒法就是當遇到需要 3 個 FB 好友才能解開後續關卡時,不要送出 request,就像現在一樣。

2013/03/23

Just a Note:SVN Repository Partial Merge

先描述一下情境,目的是要將自己開發環境的 svn 轉移到客戶的 svn repository。

客戶的 svn repository 事先就建立好,且有制定好的目錄結構,我們只是將 source 放到對應的路徑下。
現行的做法是,從開發環境 checkout 出最後一版資料,然後 commit 到客戶的 svn repository,視為全新的開始,過去的歷程就一筆勾銷。
然後開發人員便將 svn reporistory 重新指到客戶的環境。
這其實也沒什麼問題,因為客戶根本不需要知道開發期間資料來來回回異動的歷程。

只是對於沒事會常常去看歷程的人來說(<-- 就是我),歷程突然都沒了(除非連回原本的 repository),其實很困擾。

是不是有什麼辦法可以在移轉後保留原本歷程呢?因此有了這篇筆記。

2013/02/19

Just a Note:Convert Data between UTF16 String and Words

用 Java 很容易,用 javascript 完全沒頭緒......記個筆記,順便灌溉一下乾涸的 blog......

Convert data between UTF16 String and Words by using CryptoJS components.

Example:


<!DOCTYPE html>
<html>
<head>
<script src="core.js"></script>
<script src="enc-utf16.js"></script>
<script>
function testTo() {
    var data = document.getElementById("inputData").value;
    document.getElementById("result").innerHTML=CryptoJS.enc.Utf16LE.parse(data);
}
function testFrom() {
    var data = document.getElementById("inputData").value;
    var a = [];
    for(var i=0; i<data.length; i+=8){
        a.push('0x'+data.substring(i,i+8));
    }
    var words = CryptoJS.lib.WordArray.create(a);
    document.getElementById("result").innerHTML=CryptoJS.enc.Utf16LE.stringify(words);
}
</script>
</head>
<body>
<input type="text" id="inputData" />
<button type="button" onclick="testTo()">to UTF16-LE</button><button type="button" onclick="testFrom()">from UTF16-LE</button>
<div id="result"></div>
</body>
</html>


Get core.js, enc-utf16.js from CryptoJS.

Download the example code