2023年12月31日 星期日

使用 Hugo 跟 Cloudflare 架設個人品牌網站 - changyy.app



買了 changyy.app 網域好一陣子,想說該用來經營一下個人品牌,然後一直偷懶 XD 目前用 Github private repository + Hugo + Cloudflare 維護 https://changyy.app 網站,最近來換一下 Hugo theme ,再重新複習一下。

目前架設個人品牌網站,主要著重在把一些網路足跡紀錄一下,雖說 linkedin 上也是整理足跡的方式,但目的是很正式的求職路線,一些有趣的小品反而不太適合。近三年嘗試了 golang、python 和 node.js 等等外,在工作上的程式語言有盡可能切換到 Python,也試著把一些小品工具包裝成 PyPi 安裝方式作為收尾,預計就可以用來充實個人品牌網站了?!

目前架設個人網站的需求如下:
  • 把相關網站靠 link 關聯著
  • 提供撰寫簡單的條列式記錄生活
就這樣,先挑了 hugo-PaperMod 樣版來試試。

連續動作:

% hugo version
hugo v0.121.1+extended Darwin/arm64 BuildDate=unknown VendorInfo=macports

% hugo new site MyWebsite --format yaml
Congratulations! Your new Hugo site was created in /path/MyWebsite.

Just a few more steps...

1. Change the current directory to /path/MyWebsite.
2. Create or install a theme:
   - Create a new theme with the command "hugo new theme <THEMENAME>"
   - Install a theme from https://themes.gohugo.io/
3. Edit hugo.yaml, setting the "theme" property to the theme name.
4. Create new content with the command "hugo new content <SECTIONNAME>/<FILENAME>.<FORMAT>".
5. Start the embedded web server with the command "hugo server --buildDrafts".

See documentation at https://gohugo.io/.

% cd MyWebsite
% hugo serve


接著套用一下 PaperMod 樣板,稍微從他的教學 github.com/adityatelange/hugo-PaperMod/wiki 小改:

% curl -L https://github.com/adityatelange/hugo-PaperMod/archive/v7.0.zip > /tmp/v7.0.zip
% unzip /tmp/v7.0.zip -d themes/
% mkdir -p config/_default/
% cat config/_default/config.yml 
theme: "hugo-PaperMod-7.0"
% tree -L 2
.
├── archetypes
│   └── default.md
├── assets
├── config
│   └── _default
├── content
├── data
├── hugo.yaml
├── i18n
├── layouts
├── static
└── themes
    └── hugo-PaperMod-7.0

12 directories, 2 files

% hugo serve

 


最後連續動作弄了些:

% cat config/_default/config.yml 
# https://gohugo.io/getting-started/configuration/
baseURL: https://your-domain
languageCode: en-us
title: YourWebsiteName
theme: hugo-PaperMod-7.0

# https://analytics.google.com/analytics/web/?#/xxxxx/reports/intelligenthome
googleAnalytics: G-XXXXXXX

minify:
  disableXML: true
  minifyOutput: true

# https://github.com/adityatelange/hugo-PaperMod/wiki/Installation
params:
  env: production
  # https://github.com/adityatelange/hugo-PaperMod/wiki/Features#profile-mode
  profileMode:
    enabled: true
    imageUrl: https://secure.gravatar.com/avatar/MD5_Of_EmailAddress?size=120
    imageWidth: 120
    imageHeight: 120
    buttons:
      - name: open source
        url: /projects

  socialIcons:
    - name: github
      url: https://github.com/id
    - name: linkedin
      url: https://linkedin.com/in/id
    - name: blogger
      url: https://your-blog-url
    
  assets:
    favicon: https://secure.gravatar.com/avatar/MD5_Of_EmailAddress?size=128
    favicon16x16: https://secure.gravatar.com/avatar/MD5_Of_EmailAddress?size=16
    favicon32x32: https://secure.gravatar.com/avatar/MD5_Of_EmailAddress?size=32
    apple_touch_icon: https://secure.gravatar.com/avatar/MD5_Of_EmailAddress?size=128
    safari_pinned_tab: https://secure.gravatar.com/avatar/MD5_Of_EmailAddress?size=128

% tree -L 2
.
├── archetypes
│   └── default.md
├── assets
├── config
│   └── _default
├── content
│   └── projects
├── data
├── hugo.yaml
├── i18n
├── layouts
├── static
└── themes
    └── hugo-PaperMod-7.0

13 directories, 2 files

下一刻則是 Cloudflare 那邊設定 Workers & Pages 項目,就長出了 changyy.app 啦,希望 2024年還有餘力繼續擴充足跡。

2023年12月25日 星期一

Python 開發筆記 - 開發 epub-image-helper 工具,批次將圖片目錄打包成 EPUB 格式,也支援 PDF to EPUB @ macos 14.2.1, Python 3.11

記得剛出社會沒多久,被派去研究電子書領域,那時就接觸了 EPUB 格式。當時在團隊中被分配到開發 EPUB READER,例如在 HTML5 環境中,在 Browser 讀進 epub 檔案、進行 unzip 、抽出目錄、呈現書的內容。後來也做過電子書相關的應用發想,而主管們相繼離開(?),也讓我接手和接觸了貢獻 webkit 的項目(C++),可惜很多狀態都不了了之。

大概兩三週前想到 EPUB 這格式,想嘗試把照片打包成單一 EPUB 檔案,方便收藏。但大概完成七八成後,才發現有很多限制,例如電子書閱讀器上要處理大檔案時,就會陷入到電子書閱讀器的硬體規格和處理能力,甚至它實作處理 EPUB 格式的方式等,我才發現當初想要把一堆照片合成一大本應當不是正道 XD 後來還是順手練習 python open source 工具,做了一些發布,在此就筆記一下。而能妥善處理大檔案的電子書閱讀器,大概就 iOS devices 而已,實際在 iPhone SE3 上處理 500MB 的電子書EPUB也都很 OK 的。

這次挑選 ebooklib 作為 EPUB 製作的核心函式庫,當初查看 github 專案上有破千的關注,跳下去使用時才發現有些限制,也順手發了兩次 pull requests ,查閱了該專案歷年的 pull requests 活躍狀態,還是自己弄了個 ebooklib.changyy 方便自己整合

最後產出的小專案:
安裝 epub-image-helper:

% pip install epub-image-helper
% epub-image-helper | jq -r '.version'
1.0.4

使用方式可以參考 README 或是 https://github.com/changyy/epub-image-helper/tree/main/example 內的小程式庫,主要可以用 epub-image-helper 將有階層式的照片打包起來,也可以自訂一個 input.json 格式,批次把許多目錄依照一些規則打包起來,如:

% cd example/01-batch-image-to-epub
% tree .
.
├── epub
├── image2epub.py
├── input.json
└── storage
    └── url 
        ├── 001 
        │   ├── 01.jpg
        │   ├── 02.jpg
        │   └── 03.jpg
        └── 002 
            ├── 01.jpg
            ├── 02.jpg
            ├── 03.jpg
            ├── 04.jpg
            └── 05.jpg

6 directories, 10 files
% cat input.json
[
  {   
    "name": "MyPhotosA",
    "author": ["Author"],
    "books": [
      "https://localhost/001/A", 
      "https://localhost/002/B", 
      "https://localhost/003/C"
    ]   
  },  
  {   
    "name": "MyPhotosB",
    "author": ["Author"],
    "books": [
      "https://localhost/004/A", 
      "https://localhost/005/B", 
      "https://localhost/006/C"
    ]   
  }
]
% python3 image2epub.py
...
% tree epub 
epub
└── MyPhotosA
    ├── MyPhotosA01.epub
    └── MyPhotosA02.epub

2 directories, 2 files

除此之外,也支援拿 pdf 作為處理,例如把一份 pdf 內所有的圖片都抽出來打包成 EPUB 格式。

估計就告一個段落吧!這個 epub-image-helper 工具發展過程中,發現自己原先想要做的(弄成一包很大的EPUB)並非主流,就漸漸失去熱情。趁熱情還沒散去之前,先弄成一個小 open source 紀念這段2023年12月初,斷斷續續兩個週末的小產出。

2023年12月19日 星期二

macOS - 使用 Cryptomator cracker 和 Hashcat maskprocessor 官方工具來猜密碼

初老...沒想到半年前朋友推坑嘗試 Cryptomator ,不一會兒也忘記密碼了,查了一下資訊得知 Cryptomator 本身有提供破解的工具,但需要自行取產密碼清單。這時就要來搭配個 hashcat !我原本也以為是透過 hashcat 直接用,最後則是用 hashcat 的密碼產生器

整個過程:
  1. 找到 masterkey.cryptomator
  2. 使用 cryptomator 官方提供的 cracker:github.com/cryptomator/cracker
  3. 使用 hashcat 牌產生密碼檔案:github.com/hashcat/maskprocessor.git
  4. 串起來猜密碼
連續範例:

% ./mp64.bin '?a' | wc -l
      95
% ./mp64.bin '?a?a' | wc -l
    9025
% ./mp64.bin '?a?a?a' | wc -l
  857375
% ./mp64.bin '?a?a' | java -jar ~/Downloads/cracker-0.1.1-fat.jar ~/Downloads/masterkey.cryptomator
Guesses per second: 46.0
Guesses per second: 47.2
Guesses per second: 47.7
Guesses per second: 47.5
Guesses per second: 47.9
Guesses per second: 47.7
Guesses per second: 47.9
Guesses per second: 47.9
Guesses per second: 47.9
...

三個字元的密碼就有 85萬種排列組合,而在電腦上跑每秒能猜 40 左右,等於要將近 2萬秒,也就是 333 分鐘,當然也就是 5 ~ 6 小時。

2023年11月5日 星期日

Python 開發筆記 - L2 Multicast / L3 Multicast 與 IGMP Snooping 測試

幫公司測試了一下 Professional Audiovisual (ProAV) 產品在不同 switch 上的情況,剛好有分別走 L2 Multicast 跟 L3 Multicast 溝通模式,而這些設備會使用 IGMP 通報 switch ,盡可能讓 Multicast 封包不要影響不必要的網路設備,避免俗稱的流量洪水事件。

由於過去經驗都是比較上層應用,這次就多多請教 chatGPT 惡補一下知識,其中 IGMP 的知識倒是被 Cloudflare 的教學文給救贖了一下:


IGMP 是用於 IPv4 的多點傳送通訊協定,是網際網路通訊協定的第四版。IPv6 依賴於多點傳送接聽程式探索 (MLD) 進行多點傳送。IPv6 網路使用 MLD 窺探而不是 IGMP 窺探。

就這句話,我反而在想 L2 Multicast 缺少 L3 (IP層) 的封包資訊,是不是讓 switch 做不到 IGMP snooping 功能?甚至舊款 switch 直接判定是未知 multicast 而進行永久性 broadcast 容錯設計?實測的結果是不同的 switch 行為是不一樣的。

整體上只需要簡單的 python 小程式,透過 scapy 套件,可非常輕鬆拼湊出想製作的 raw socket 來進行測試:

RX app: 

from scapy.all import *
from scapy.contrib.igmp import IGMP

multicastMac = "01:00:5e:00:02:01"
multicastGroupIP = '224.0.2.1'
nicName = '乙太網路'

# IGMPv2 Membership Report
igmpReportPacket = Ether(dst=multicastMac)/IP(dst=multicastGroupIP)/IGMP(type=0x16, mrcode=0, gaddr=multicastGroupIP)
sendp(igmpReportPacket, iface=nicName)

while True:
    multicastReceivePacket = sniff(iface=nicName, filter=f"ether dst {multicastMac}", count=1)
    if multicastReceivePacket:
        print("Received: ", multicastReceivePacket[0][Raw].load.decode("utf-8"))
        #print("Received: ", multicastReceivePacket[0][Raw].load)

TX app:

from scapy.all import *
from scapy.contrib.igmp import IGMP

multicastMac = "01:00:5e:00:02:01"
multicastGroupIP = '224.0.2.1'
nicName = '乙太網路2'

# IGMP Membership Report
igmpReportPacket = Ether(dst=multicastMac)/IP(dst=multicastGroupIP)/IGMP(type=0x16, mrcode=0, gaddr=multicastGroupIP)
sendp(igmpReportPacket, iface=nicName)

i = 0
while True:
    # Multicast
    if i % 3 == 0: 
        multicastTestMessagePacket = Ether(dst=multicastMac, type=0xffff)/"hello"
    elif i % 3 == 1:
        multicastTestMessagePacket = Ether(dst=multicastMac)/IP(dst=multicastGroupIP)/UDP(sport=12345, dport=12345)/"world"
    else:
        multicastTestMessagePacket = Ether(dst=multicastMac)/IP(src="192.168.1.2", dst=multicastGroupIP)/UDP(sport=12345, dport=12345)/"hello world"

    sendp(multicastTestMessagePacket, iface=nicName)

    # IGMPv2 Report
    if i % 600:
        sendp(igmpReportPacket, iface=nicName)
    i += 1

    time.sleep(1/10)

如此,弄一台筆電,讓他上頭有兩張 RJ45 網卡(可靠USB擴充),分別插上待側的 switch ,一邊當 RX 收訊息,另一邊當 TX 送訊息,接著調整 switch 設定後,觀察封包傳遞的狀況。可以的話,其實筆電可以設法弄個 3個網孔?接著另一網孔可以插在 switch 上,看看有沒有流量洪水(traffic floods)

收工

2023年10月12日 星期四

SSD 外接硬碟盒 與 USB3.2 Gen 1 / USB3.2 Gen 2 / USB3.2 Gen 2x2 / USB 4 規格 @ 以 2023 MacBook Air 15吋 M2 使用為例

最近準備升級工作環境,正在評估外接硬碟方案,主因是買的 Type-C 隨身碟很容易掛 :P 先對照著 2023 Macbook Air 15吋 M2 的規格:

兩個 Thunderbolt / USB 4 埠,可支援:

充電
DisplayPort
Thunderbolt 3 (速度最高可達 40Gb/s)
USB 4 (速度最高可達 40Gb/s)
USB 3.1 Gen 2 (速度最高可達 10Gb/s)


這這邊提到 USB4 和 USB 3.1 Gen 2,跟 chatGPT 請教一下,原來 USB3.2 的各代基本上也是用來簡述以前 USB 3.1, USB 3.0 等用法,直接查看 USB 3 WIKI - zh.wikipedia.org/zh-tw/USB_3.0
  • USB 3.2 Gen 1x1 == USB 3.2 Gen 1 == USB 3.1 Gen 1 == USB 3.0
  • USB 3.2 Gen 1x2 (只支援 Type-C)
  • USB 3.2 Gen 2x1 == USB 3.2 Gen 2 == USB 3.1 Gen 2
  • USB 3.2 Gen 2x2 (只支援 Type-C)
然後頻寬就 USB 3.2 Gen 1 = 5 Gbit/s, USB 3.2 Gen 2 = 10 Gbit/s,因此上述依序就是 5 Gbit/s, 10 Gbit/s, 10 Gbit/s, 20 Gbit/s ,這樣就好記許多。而上述通常會簡化成以下三款:
  • USB 3.2 Gen 1 = 5 Gbit/s 傳輸效率 = 理論上約略每秒 500MB 傳輸效率
  • USB 3.2 Gen 2 = 10 Gbit/s 傳輸效率 = 理論上約略每秒 1000MB 傳輸效率
  • USB 3.2 Gen 2x2 = 20 Gbit/s 傳輸效率 = 理論上約略每秒 2000MB 傳輸效率
而 MacBook Air 15吋 M2 版的規格描述就是 USB4 (40Gb/s) or USB 3.1 Gen 2 (10Gb/s)。若不需衝極值,就買支援 USB 3.1 Gen 2 版的外接硬碟即可。此刻也可以採買到 USB 4 的外接SSD盒,通常會詳加描述自己的散熱系統。

此外,在 SSD 規格上,常見 M.2 PCI Express 2280, M.2 PCI Express 2260, M.2 PCI Express 2242, 後面那串數字 2280, 2260, 2242 代表寬x長等於 22x80, 22x60, 22x42,而 PCI Express 也會看的 PCIe 3.0 和 PCIe 4.0 ,其中 PCIe 3.0 每個通道傳輸效率 8 Gbit/s 而 PCIe 4.0 每個通道傳輸效率 16 Gbit/s,例如一款產品名為 M.2 2280 PCIe Gen3x4 ,代表該 SSD 插槽規格為 M.2 規格,寬長 22x80 ,傳輸速度是 Gen3x4 = 8 Gbit/s x4 = 32 Gbit/s = 理論上傳輸效率約 4 GB/s

而上面的傳輸效率都是 "理論上" ,實際上傳輸速度還會跟 SSD 內部控制器晶片、NAND閃存類型以及操作的檔案大小和數量等有關。

關於 SSD 保固上,常見 5年保固 或 600 TBW 有限保固,後者代表寫入達 600 TB 的資料量概念,通常 SSD 空間越大時,保固的 XXX TBW 數字會越大,例如 1TB SSD 會有 600 TBW ,而 2TB 就會常看到 1000 TBW 等有限保固機制。

最後,回到最初的想法,會思考 SSD 外接盒起源於一顆 512GB USB3.2Gen1 隨身碟經常性備份資料或埋了很多零碎檔案後,容易壞掉 :P 

例如插上 Macbook 無法被偵測,甚至無法被修復,後來交叉用 Windows 11 修復,回來在 macOS 又可以辨識到...但這樣的日子太不安穩了,因此評估一下是否在掏錢買個 SSD + 外接盒方案,如此 SSD 可抽換+保固服務長



2023年10月10日 星期二

Python 開發筆記 - Ping 與 WakeOnLan (WOL) 的應用

這假期恰逢公司機房斷電,復電後在想該怎樣把重要的機器喚起。由於 VPN 等相關機器群健康運作(如套裝 NAS 機器),因此得以遠端回去做事。

下一刻就是回顧有哪些機器要遠端啟動,這時就多虧了強者同事有良好的筆記習慣,平時有撰寫 WIKI 管控機器群(包括 MacAddress),就這樣,可在指定機器上不斷發動 WOL 來喚醒。例如有些 router 本身就提供網頁介面幫忙,可以直接靠他們。若有 Ubuntu 機器,就來個 wakeonlan 工具:

$ dpkg -l | grep wakeonlan
ii  wakeonlan                              0.41-10                                 Sends 'magic packets' to wake-on-LAN enabled ethernet adapters

在這邊 ubuntu.pkgs.org/20.04/ubuntu-main-arm64/wakeonlan_0.41-12_all.deb.html 也能查看到,甚至瀏覽一下工具原始碼 github.com/jpoliv/wakeonlan ,而 WOL 的原理可以查看 WIKI 就習得實作技能 en.wikipedia.org/wiki/Wake-on-LAN 或詢問 chatGPT 也會很佛心。

假期期間,就弄個 python 工具 ping-before-wakeonlan ,目的是為了記錄此次喚起了幾台機器,可以限縮每次喚起的機器數量,避免一堆機器一起起來而造成電力需求過大而跳電,另外再加入把清單亂數排一下,避免前面清單的機器都無法喚起,又讓清單後面的機器沒機會被叫起來:


使用方式,主要為 `pip install ping-before-wakeonlan` 即可,以下是 venv 用法:

% python3 -m venv venv
% source venv/bin/activate
% pip install ping-before-wakeonlan
% ./venv/bin/ping-before-wakeonlan
% cat /tmp/device.json
[
   {
       "ip": "192.168.1.1",
       "mac_address": "00:00:00:00:00:01"
   },
   {
       "ip": "192.168.1.2",
       "mac_address": "00:00:00:00:00:02"
   },
   {
       "ip": "192.168.1.3",
       "mac_address": "00:00:00:00:00:03"
   }, ...
]

% ping-before-wakeonlan --device-info /tmp/device.json
Process: 1 / 7: Device: {'ip': '192.168.1.3', 'mac_address': '00:00:00:00:00:03'}
Process: 2 / 7: Device: {'ip': '192.168.1.2', 'mac_address': '00:00:00:00:00:02'}
Process: 3 / 7: Device: {'ip': '192.168.1.1', 'mac_address': '00:00:00:00:00:01'}
Process: 4 / 7: Device: {'ip': '192.168.1.4', 'mac_address': '00:00:00:00:00:04'}
Process: 5 / 7: Device: {'ip': '192.168.1.5', 'mac_address': '00:00:00:00:00:05'}
{
    "count": 5,
    "device": {
        "failed": [],
        "handled": [
            {
                "ip": "192.168.1.3",
                "mac_address": "00:00:00:00:00:03"
            },
            {
                "ip": "192.168.1.2",
                "mac_address": "00:00:00:00:00:02"
            },...
        ],
        "input": [
            {
                "ip": "192.168.1.3",
                "mac_address": "00:00:00:00:00:03"
            }, ...
        ],
        "online": [],
        "skip": [
            {
                "ip": "192.168.1.6",
                "mac_address": "00:00:00:00:00:06"
            }, ...
        ]
    },
    "info": [
        "..."
    ],
    "maxCount": 5,
    "ping": "ping -c 1 -W 3",
    "status": true,
    "version": "1.0.0"
}

2023年10月4日 星期三

Python 開發筆記 - 使用 Gitlab API 列出 Projects、Branches 和 Commits

剛好碰到需要製作 Gitlab 整合類服務,開發完後就把很基礎的項目整理成小工具來支援 JSON 輸出,未來可以跟 jq 做一堆連續技:

用法:

% virtualenv venv
created virtual environment CPython3.11.5.final.0-64 in 120ms
...

% source venv/bin/activate
(venv) % 
(venv) % pip3 install gitlab-api-helper
(venv) % ./venv/bin/gitlab-api-helper 
{
    "info": [
        "config file not found: .env",
        "--api empty"
    ],
    "result": null,
    "version": "1.0.0"
}
usage: gitlab-api-helper [-h] [--apiSetupConfig APISETUPCONFIG]
                         [--apiAccessToken APIACCESSTOKEN] [--api API]
                         [--sinceType {day,week,month}]
                         [--sinceNumber SINCENUMBER]
                         [--lookup {project,branch,commit}]
                         [--lookupProjectID LOOKUPPROJECTID]
                         [--lookupBranch LOOKUPBRANCH]

A Simple Tool for Gitlab API Usage

options:
  -h, --help            show this help message and exit
  --apiSetupConfig APISETUPCONFIG
                        Read Default Info from config file
  --apiAccessToken APIACCESSTOKEN
                        Using Gitlab API with private_token.
  --api API             Gitlab API URL
  --sinceType {day,week,month}
                        commit date range type
  --sinceNumber SINCENUMBER
                        commit date range value
  --lookup {project,branch,commit}
                        query result
  --lookupProjectID LOOKUPPROJECTID
                        Gitlab Project ID
  --lookupBranch LOOKUPBRANCH
                        Branch Name

剩下就看 github.com/changyy/gitlab-api-helper 或 pypi.org/project/gitlab-api-helper/ 的簡介囉

2023年10月3日 星期二

PHP 開發筆記 - 用 Matomo Analytics HTTP API 取代 GA4 Measurement Protocol 服務 @ Ubuntu 22.04


由於 Google Analytics 4 在後端端數據搜集情境已殘,可能起源於 GA4 著重隱私等設計(?),現況數據收集已強調必須先從 Web or App 開始,透過 JS SDK 或 APP SDK 做事,而後端回報為輔助而已,在 Web & App 端可以做隱私宣告。如此,使得純後端回報幾乎無法妥善使用 GA4 的功能,包括無法區分 new user / old user 屬性等等,也不像 GA3 可以把 remote client 的 IP 回報出去而顯示使用者的世界全貌。

架設 Matomo 方式還滿簡單的,就 Web Server + PHP + MySQL ,並且官方也有 docker 安置方式:

由於看到別人的文章提到要記得設置定期分析任務,不然久久登入網頁會很卡的,推論也是從網頁端發送查詢資料,過程中也一同處理資料分析。這個用瀏覽器時,從開發者工具中也可以看到定期在發送 ajax 的 requests。


目前就先弄個 Matomo project 出來,根據上頭的指示很簡單就埋好 js script code 去追蹤網站流量,可以看得到 Matomo 比 GA 提供更多細膩的資訊,這就像隱私的那些規劃,在 GA 上頭只能很粗略地觀看到“趨勢”,而在 Matomo 上頭,則是可以細到把指定的 client 展開出他的 Profile:


我認為跟 GA 相比有滿明顯的設計差距。

接著,關於透過 REST API 回報數據與查詢回報的方式,可以參考:

回報 PageView/Event:

% cat test.php
require 'report.php';

print_r(matomoPageview(
[
[
'url' => 'http://localhost/page1',
'action_name' => 'PageView 01 - Title',
'uid' => '123456789012',
//'cip' => getUserIP(),
],
[
'url' => 'http://localhost/page2',
'action_name' => 'PageView 02 - Title',
'uid' => '123456789012',
//'cip' => getUserIP(),
],
[
'url' => 'http://localhost/page3',
'action_name' => 'PageView 03 - Title',
'uid' => '123456789012',
//'cip' => getUserIP(),
'e_c' => 'Service',
'e_a' => 'Auth',
'e_n' => 'Login',
],

]
,'idSite'
,'MatomoAPI'
));

% php test.php
Array
(
    [status] => 1
    [error] => 
    [info] => Array
        (
            [0] => Array
                (
                    [apiResult] => {"status":"success","tracked":1,"invalid":0}
                )

        )

)

得到 Report:

% cat test.php
require 'report.php';

print_r(matomoQueryReport(
        [   
                'idSite' => 1,
                'period' => 'day',
                'date' => '2023-10-01,2023-10-03',
                'method' => 'VisitsSummary.get',
        ]   
        , 'https://your-matomo.example.com/'
        , 'access_token'
));

% php test.php
Array
(
    [status] => 1
    [data] => Array
        (
            [0] => Array
                (
                    [2023-10-01] => Array
                        (
                        )

                    [2023-10-02] => Array
                        (
                        )

                    [2023-10-03] => Array
                        (
                            [nb_uniq_visitors] => 1
                            [nb_users] => 1
                            [nb_visits] => 1
                            [nb_actions] => 2
                            [nb_visits_converted] => 0
                            [bounce_count] => 0
                            [sum_visit_length] => 1
                            [max_actions] => 2
                            [bounce_rate] => 0%
                            [nb_actions_per_visit] => 2
                            [avg_time_on_site] => 1
                        )

                )

        )

    [error] => 
    [info] => Array
        (
        )

)

2023年9月26日 星期二

[Linux] OpenSSL AES-128 加解密 @ macOS 13.2.1, OpenSSL 3.1.2 1 Aug 2023

總覺得我是不是以前也寫過這類筆記? 查了下快十年前 XD 用的是 openssl des3 

由於工作中太常接觸 AES-128 加解密了,想要筆記一下方便未來查詢,而透過 openssl command 也方便交叉驗證程式是否正確,這次就仿 openssl des3 筆記:

明文:

% cat /tmp/input.txt
Hello World
% md5 /tmp/input.txt
MD5 (/tmp/input.txt) = e59ff97941044f85df5297e1c302d260
% hexdump /tmp/input.txt 
0000000 6548 6c6c 206f 6f57 6c72 0a64          
000000c

產生加解密的 Key 值:

% dd if=/dev/urandom of=/tmp/password bs=1 count=32
32+0 records in
32+0 records out
32 bytes transferred in 0.000303 secs (105611 bytes/sec)
% md5 /tmp/password 
MD5 (/tmp/password) = 92eeb8e1bec70865650e1f96e5cd1819
% hexdump /tmp/password 
0000000 cf23 5006 70d0 bf1e 0e9e a70c 10f0 ecd6
0000010 dc01 e156 d818 bff2 2e3e f859 28c9 a91d
0000020
% hexdump -v -e '/1 "%02x"' -n 16 /tmp/password 
23cf0650d0701ebf9e0e0ca7f010d6ec

產生加解密的 IV 值(其實同 Key 值產生即可,目前改用另一招):

% date | md5
5d6476c85eca3ec56fda4913f5578b83

使用 OpenSSL AES-128 加密:

% openssl enc -e -aes-128-cbc -in /tmp/input.txt -out /tmp/encrypt.txt -K 23cf0650d0701ebf9e0e0ca7f010d6ec -iv 5d6476c85eca3ec56fda4913f5578b83
% hexdump /tmp/encrypt.txt
0000000 c3d4 cb0a d845 182c 319e afdf b29c c484
0000010

使用 OpenSSL AES-128 解密:

% openssl enc -d -aes-128-cbc -in /tmp/encrypt.txt -out /tmp/output.txt -K 23cf0650d0701ebf9e0e0ca7f010d6ec -iv 5d6476c85eca3ec56fda4913f5578b83
% md5 /tmp/output.txt 
MD5 (/tmp/output.txt) = e59ff97941044f85df5297e1c302d260
% cat /tmp/output.txt 
Hello World

工作上很容易 Key 值是一個 32 bytes 的 binary 檔案,且不加入輸出至檔案的方式,可以立即看解密的內容,連續動作如下:

% openssl enc -d -aes-128-cbc -in /tmp/encrypt.txt -K $(hexdump -v -e '/1 "%02x"' -n 16 /tmp/password) -iv 5d6476c85eca3ec56fda4913f5578b83
Hello World

收工

2023年9月20日 星期三

Windows 開發筆記 - 使用 Command Line / CMD / ssh 與 PHP 8.2 / Composer / Git / VIM 開發環境 @ Windows 11

幫同事看了一下 Windows 開發環境,要在此環境使用 PHP8.2 與 PHP Laravel v10 framework,由於之前採用 xampp 管理套件被環境變數卡住。這些問題描述,瞬間拉回到學生時代在那邊設置 Windows %PATH% 環境變數 XD 我也忘了那時在幹嘛?推論是配置 Java 環境吧

目前就把手邊的 Windows 11 筆電拿來遠端,但懶得打開它。並且實際在 command line 測試會碰到幾個問題。

1. 從 https://windows.php.net/download/ 下載 VS16 x64 Non Thread Safe ,並解壓在 C:\php 目錄中,必須在設置 php.ini 。想要知道自己的 php.ini 位置,可以用 php.exe --ini

C:\php>php.exe --ini 
Configuration File (php.ini) Path: 
Loaded Configuration File:         (none)
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

接著把 C:\php\php.ini-development 複製到 C:\php\php.ini 使用:

C:\php>copy php.ini-development php.ini     
複製了         1 個檔案。

後續就編輯 php.ini 開啟一些項目,在此就靠 C:\cygwin64\bin\vim.exe 當編輯器(若碰到滑鼠圈選文字難複製,記得關掉滑鼠模式 :set mouse-=a),主要打開一些 php.ini 註解:

; Directory in which the loadable extensions (modules) reside.
; https://php.net/extension-dir
;extension_dir = "./"
; On windows:
extension_dir = "ext"
; ...
extension=curl
extension=fileinfo
extension=gd
extension=intl
extension=mbstring
extension=exif
extension=mysqli
extension=openssl
extension=sqlite3

C:\php>php.exe --ini 
Configuration File (php.ini) Path: 
Loaded Configuration File:         C:\php\php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed:      (none)

2. 下載 composer 後,預設會失敗:

C:\php>php.exe composer.phar self-update

In Factory.php line 648:
                                                                                                                          The openssl extension is required for SSL/TLS protection but is not available. If you can not enable the openssl extension, you can   
   disable this error, at your own risk, by setting the 'disable-tls' option to true.                          

self-update [-r|--rollback] [--clean-backups] [--no-progress] [--update-keys] [--stable] [--preview] [--snapshot] [--1] [--2] [--2.2] [--set-channel-only] [--] [<version>]

設置後:

C:\php>php.exe composer.phar self-update 
You are already using the latest available Composer version 2.6.3 (stable channel).

3. 在管理專案時,透過 C:\php\php.exe composer.phar install 時,會需要 GIT 指令,解法就是去官方安裝一下,安裝完的目錄位置在 C:\Program Files\Git 位置

C:\>"C:\Program Files\Git\bin\git.exe" --version
git version 2.42.0.windows.2

4. 回過頭來,更新環境變數 %PATH% 

C:\>git
'git' 不是內部或外部命令、可執行的程式或批次檔。
C:\>echo %PATH%
C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Docker\Docker\resources\bin;C:\WINDOWS\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps;C:\Users\user\AppData\Local\Microsoft\WindowsApps;
C:\>set PATH=%PATH%;C:\Program Files\Git\bin\
C:\>git --version
git version 2.42.0.windows.2

如此在 Windows 的 command line (PowerShell) 環境下,也可以靠純指令做一點事了

2023年9月14日 星期四

Docker 開發筆記 - 建立私有的 DockerHub 服務 / My Private Docker Registry

對於公司內的 Docker 使用,當然就不能把一堆程式碼都擺在外頭的 dockerhub 來管理,所幸的 Docker Registry 也可以透過 Docker 快速建立,並且把資料儲存那段跟指定的機器儲存結合,瞬間立馬建置完畢:

Docker Registry - docs.docker.com/registry/

操作:

% docker run -d -p 5000:5000 -v /tmp/registry-stoarge:/var/lib/registry --name registry registry:2 
Unable to find image 'registry:2' locally
2: Pulling from library/registry
...: Pull complete 

% docker container list
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                    NAMES
1ab332dd4bb5   registry:2   "/entrypoint.sh /etc…"   21 seconds ago   Up 20 seconds   0.0.0.0:5000->5000/tcp   registry

將 image 發佈到指定的 Docker Registry server:

% docker image list
REPOSITORY             TAG       IMAGE ID       CREATED        SIZE
my/test                1.0.0     9b400be021d8   25 hours ago   457MB
registry               2         0030ba3d620c   5 weeks ago    24.1MB

% docker tag my/test:1.0.0 localhost:5000/my/test
% docker push localhost:5000/my/test
Using default tag: latest
The push refers to repository [localhost:5000/my/test]
............: Pushed 
............: Pushed 
............: Pushed 
latest: digest: sha256:...........
 size: ...

列出指定的 Docker Registry server 上的 image list:

% curl localhost:5000/v2/_catalog
{"repositories":["my/test"]}

列出指定的 Docker Registry server 上的 image 上的 tag list:

% curl localhost:5000/v2/my/test/tags/list
{"name":"my/test","tags":["latest"]}

查看一下 /tmp/registry-stoarge 內已經儲存的資料結構:

% tree -L 7 /tmp/registry-stoarge
/tmp/registry-stoarge
└── docker
    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── ...
            │       │   └── ...
            │       └── ...
            │           └── ...
            └── repositories
                └── my
                    └── test
                        ├── _layers
                        ├── _manifests
                        └── _uploads

30 directories, 0 files

最後,使用 Docker Registry server 上的 image 做事:

% docker run -it localhost:5000/my/test
root@.....:/# ls

2023年9月7日 星期四

Windows 開發筆記 - 開機自動啟動 SSH Reverse Tunnel / autossh @ Windows 11, cygwin

視窗鍵 + R 輸入 shell:startup

想說要善加利用 Windows 筆電,就想到把它規劃成算力單位後,以及思考如何自動化叫他做事。在資安角度上就可採用 SSH Reverse Tunnel 方案,讓筆電開機啟動後,建立一個連線到指定的機器候命。如此,在 Windows 筆上安裝了一些服務後,就可以用遠端 Port Forwarding 的方式存取到。

首先,要先找到 autossh 這種用法,不然單建立一個 ssh 掛了很麻煩的。雖然有一些 github 的可挑,但整體上要找一個夠信任的來源,最後選擇知名的 cygwin ,就順便安裝 autossh, tmux, vim, wget, lftp, git, zip, unzip 等,如此 autossh.exe 就搞定,位置在 C:\cygwin64\bin\autossh.exe

之前的文章已提到,我在 Windows 11 下已啟用 OpenSSH server 了,那我可以測試把 openssh server 服務建立反向的連線(須留意 cygwin 認定的使用者家目錄跟 Windows PowerShell 的不一樣,需要先建立好 keypair 等資料)

C:\cygwin64\bin\autossh.exe -M 0 -N -R 10022:localhost:22 ServerUser@RemotServer

如此,在指定的機器(RemoteServer)上,就可以測試連線:

$ telnet localhost 10022
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
SSH-2.0-OpenSSH_for_Windows_8.6
^C^C
Connection closed by foreign host.

對於 cygwin 方面,目前採用 Windows 內建的 OpenSSH server 方案,連入後是 Windows Powershell 環境,若想切換到 cygwin ,可以多打一下:

Microsoft Windows [版本 10.0.22621.2215]

(c) Microsoft Corporation. 著作權所有,並保留一切權利。


user@WINDOWS-DESKTOP C:\Users\user>c:\cygwin64\Cygwin.bat


user@windows-desktop ~

$ 


對於 cygwin 用法,正規的安裝軟體還是透過原本的 setup.exe 去擴充,然而,可以去下載 github.com/transcode-open/apt-cyg 來使用,他可以提供一些便利的 command line 安裝套件的方式(但實務上不幸踩過失敗),當作一個備用方式:

user@windows-desktop ~

$ curl -s https://raw.githubusercontent.com/transcode-open/apt-cyg/master/apt-cyg > apt-cyg


user@windows-desktop ~

$ chmod 700 ./apt-cyg 


user@windows-desktop ~

$ ./apt-cyg 

NAME

  apt-cyg - package manager utility


SYNOPSIS

  apt-cyg [operation] [options] [targets]


DESCRIPTION

  apt-cyg is a package management utility that tracks installed packages on a   

  Cygwin system. Invoking apt-cyg involves specifying an operation with any     

  potential options and targets to operate on. A target is usually a package    

  name, file name, URL, or a search string. Targets can be provided as command  

  line arguments.


OPERATIONS

  install

    Install package(s).


  remove

    Remove package(s) from the system.


  update

    Download a fresh copy of the master package list (setup.ini) from the       

    server defined in setup.rc.


  download

    Retrieve package(s) from the server, but do not install/upgrade anything.   


  show

    Display information on given package(s).


  depends

    Produce a dependency tree for a package.


  rdepends

    Produce a tree of packages that depend on the named package.


  list

    Search each locally-installed package for names that match regexp. If no    

    package names are provided in the command line, all installed packages will 

    be queried.


  listall

    This will search each package in the master package list (setup.ini) for    

    names that match regexp.


  category

    Display all packages that are members of a named category.


  listfiles

    List all files owned by a given package. Multiple packages can be specified 

    on the command line.


  search

    Search for downloaded packages that own the specified file(s). The path can 

    be relative or absolute, and one or more files can be specified.


  searchall

    Search cygwin.com to retrieve file information about packages. The provided 

    target is considered to be a filename and searchall will return the

    package(s) which contain this file.


  mirror

    Set the mirror; a full URL to a location where the database, packages, and  

    signatures for this repository can be found. If no URL is provided, display 

    current mirror.


  cache

    Set the package cache directory. If a file is not found in cache directory, 

    it will be downloaded. Unix and Windows forms are accepted, as well as      

    absolute or regular paths. If no directory is provided, display current     

    cache.


OPTIONS

  --nodeps

    Specify this option to skip all dependency checks.


  --version

    Display version and exit.


下一步回歸到正題 - 開機自動執行,則是可以參考微軟官方文件 - 新增的應用程式以在 Windows 10 啟動時自動執行。此例在 Windows 11 上,透過 視窗鍵+R 執行 shell:startup 可快速開啟對應的目錄位置 ( %HOME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup ),只需在此目錄添加幾個 bat 檔案,開啟就會幫我運行這指令了,如:

00_ssh-reverse-tunnel_openssh-server.bat

內容:

C:\cygwin64\bin\autossh.exe -M 0 -N -R 10022:localhost:22 ServerUser@RemotServer

開啟後,他會佔一個小視窗。由於那台筆電本身就是閒置的,所以佔著小視窗反而更好觀測 autossh 運作是否正常

收工!