2020年6月2日 星期二

[Linux] AddTrust External CA Root expired 處理方式 @ Ubuntu

週日也不幸踩到這個雷了,當時只解了幾個,沒想到這個範圍很大很大。
故事是我們採用 Namecheap 服務來簽署 Wildcard SSL 憑證,而使用到 AddTrust External CA Root 簽署。

當 AddTrust External CA Root 有效期間只到 2020/05/30 10:48:38 時,時間一到後,導致用戶連到我們的服務產生失敗,以 curl 來說,他預設依賴 OS 提供的系統憑證資訊:

$ curl https://ourservice.exmaple.com
curl: (60) server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

而 Chrome Browser 很佛心,從軟體層自動幫轉到 USERTrust RSA Certification Authority。

問題的解法:

正確解法:直接再重新簽核新的憑證,新的憑證簽署時會略過已過期的項目。
臨時解法:將 https client side 的 AddTrust External CA Root 註解起來 

臨時解法,以 Ubuntu 內的 https client 為例,將 mozilla/AddTrust_External_Root.crt 那行註解起來

$ sudo vim /etc/ca-certificates.conf && sudo sh -c 'apt update && apt install ca-certificates && update-ca-certificates -f -v'

臨時解法只能解決 https client 是已知的範圍,像是服務的 client 都是自己控制的,這時就可以先解決那些 client 憑證的檢驗機制,但追到更細時,大部分的 https client 靠 OS 提供的憑證資訊就只要改一次,如果 https client 上跑 node.js 等應用,他們可能會依賴其他相關套件來維護憑證資訊,不一定會用 OS 內紀錄的憑證資訊,這時要排除會非常痛苦。因此,正確解法是重新簽發憑證

2020年5月19日 星期二

Shopify 開店筆記 - 跨境電商、依重量計算運費、依地區限制購物

google SHOP stock 2020/05/16

約莫協助公司維運自家電商已經有五年多。

通常電商的成績不佳,大部分會被認為是電商平台的設計問題,像是購物流程是否可以改善、網站配色是否不夠精美等等。因此,我們也開始研究是否朝向知名的網購平台 Shopify 來維運。Shopify 是一個體質非常好的電商平台,非常適合小試身手的平台,而這波疫情也讓 Shopify 股價扶搖直上。

其實,公司維運的電商平台老早就有用 Shopify 幾年了,如幫其他客戶經營副牌、白牌等。對我而言是一個熟悉又陌生的平台,因為整體上的維運都已經不需要透過工程師。趁這次把品牌電商遷移到 Shopify 上,順手記錄碰到的課題,主要分成收錢(金流)、寄貨(物流)、買家交易過程和其他需求等筆記,而 Shopify 其實有不錯的 Shopify App Store,可以自行添購(通常是訂閱式,每月支付),有些真的滿夠用,十分方便。

收錢/金流:

提供常見的 Paypal 支付,以及 Shopify Payment 機制,而這兩點都恰好因為已有 Paypal 帳號跟有香港辦公室的關係無痛打通。這兩個金流的使用都有地緣限制,像 Shopify Payment 還可以有 Google pay / Apple Pay ,只是不見得買家的地方可以使用。

金流上當客戶在網站上完成支付後,Shopify 便會立即發信給 商店聯絡電子郵件,就是在 "後台 -> 設定 -> 一般 -> 商店聯絡電子郵件" 設定。

此外 Paypal 帳號也是只限制 PayPal 商業帳戶,不能用個人的。

寄貨/物流:

Shopify 的物流可以簡單到自己寄送即可,單純把訂單標記成已出貨,並且可以填寫 tracking code 及查詢的方式(使用的物流),就完成了!

而物流的複雜度其實可大可小,我認為比較重要的是運送費率的設計,Shopify 支援設定多個倉儲位置,假設設定了兩個處(香港和台灣),那必須替這兩個倉儲分別設定運送策略。假設只對香港設定寄送到全世界而台灣倉庫沒有任何運送設定,這時有一位台灣用戶下單時,他會被默認靠近台灣而使用台灣倉庫的寄送策略,但台灣倉庫沒設定運送到台灣的運費規則,而導致使用者無法完成下單(會顯示類似無法寄送的錯誤訊息)。

另外,若設計以重量方式計算運費時,假設以 0.5kg 為間隔單位,分別設定了 "小於0.5kg"、"0.5kg到1.0kg"、"1.0kg到1.5kg",1.5kg到2.0kg",這時若使用者買的東西總重落在 2.0kg 以下是可以的,且有運費合併計算的美意,但如果使用者買的總重量超過 2.0kg 時,一樣會落入無法寄送的錯誤訊息,因為沒有大於 2.0kg 的運費規則。

另外,也要留意裝箱的箱子重量,定義了依重量計費時,結果不如預期時,可能是箱子重量影響。

買家交易過程:

如果沒有調整過預設設定時,客戶在下單過程時,可以選用手機門號簡訊完成認證,快速驗身完就可以下單了,非常貼心。而訂單狀態會用簡訊通知對方。然而,若是在做跨境電商時,碰到訂單問題時,就得走電話聯繫,推論會十分痛苦。另一方面,快遞都會要求填寫聯絡電話,若客戶訂購時沒留下電話資訊也會很苦的。

因此,將會到 "後台 -> 設定 -> 結帳",在 "客戶聯絡" 方面,改成限定用 email 結帳。表單資訊,會要求填寫 "運送地址電話號碼"。作為跨境電商的訂單管理機制。

其他項目 - 賣樣品給客人:

Shopify 建立訂單草稿 是非常好用的項目!若業務想要銷售樣品給客人時,透過訂單草稿,可以自行打包幾個商品、給予折扣,再透過寄送電子發票,便直接通報客戶直接到 Shopify 付款,整個過程非常方便。讓業務很快地辦完事,負責金流物流的同事也只是例行處理自己的職責。十分完美。

可以多多參考 Shopify 的說明:訂單草稿

其他項目 - 提醒未完成結帳項目:

當用戶在 Shopify 平台下單時,未完成結帳的訂單,一樣在後台可以看到。Shopify 可以在 "後台 -> 設定 -> 結帳 -> 未完成結帳作業" ,設定幾小時後傳送提醒信件。如此可以設法拉回一些潛在用戶。

其他項目 - 跨境電商 - 依照地區給予不同價格:

這個應數主要是總代理跟代理之間的關係,如果某個地區有代理商了,總代理賣的價格通常不能低於代理商,不然代理商都賣不出貨了。面對這個需求有兩種解法,第一種就是故意在電商上不銷售到有代理商的區域,可以靠 運費費率 的設定,讓有代理商地區沒有運費規則,這樣用戶就不能下單。另一種要花點錢的機制,使用 Multi-Country-Pricing 等類似服務,依照地區給予不同價格,但 Shopify 的核心只有收一個幣別,就算透過 Multi-Country-Pricing 的機制能夠給予當地使用者觀看當地的幣值,最終在收費時,還是會轉回原先 Shopify 商店所規範的價格(如美金為單位)


其他項目 - 信件通知:

Shopify 會用 "後台 -> 設定 -> 一般 -> 商店詳細資訊 -> 客戶電子郵件" 當作 mail sender 發送。通常 Shopify 發送到自己管理的 mail server 時,可以透過 SPF record 來允許,增加信件不被規範到垃圾信中。只有時很慘的,自家 mail server 阻擋了 Shopify 寄來的信時,只能設法靠不同的 mail domain 來避開。


在不同 mail domain 避開的機制下,例如現在用 [email protected] 作為 商店聯絡電子郵件 ,只好再用 [email protected] 當作 客戶電子郵件 。此時必須記得去修改信件通知的資訊,避免信件通知信一直請客人寄信給 [email protected] 尋求客服。而 [email protected] 最好也在設定個自動轉寄到 [email protected] ,避免漏掉客戶的重要信件。願意花錢可以靠 AWS WorkMail 單一帳號一個月四美金頂著用,不願意花錢可以試試免錢的 Yandex.Mail 。

2020年5月8日 星期五

[Python] 使用 http.server.BaseHTTPRequestHandler 製作簡易 Proxy 機制 @ macOS, python 3

學會用 curl / wget 模仿一些 request 後,在一些特殊情境上,還是得弄個 proxy 出來,雖然有 man-in-the-middle Proxy: mitmproxy 可以使用,但有時就是想要單純一點,寫點小程式自娛一下 XD

故事的情境:

- 想用 VLC 播放一些 Streaming 來源,但該 streaming 在存取時要求多塞一些request header,直接播會收到 40X 回應
- VLC 預設只吃 OS Level 的 proxy 設定

基於上述情境,雖然靠 curl/wget 添加 request header 可以搞定,但 VLC 這類就無法達成播放指定來源時多添加 request header。

因此,除了靠 OS Level 的 Proxy server 添加 reader header,就剩寫一隻代抓資料,邊抓邊輸出 stream 的小小程式,程式碼:

import http.server
import urllib.parse
import requests
import time

class ProxyHTTPRequestHandler(http.server.BaseHTTPRequestHandler):
	protocol_version = 'HTTP/1.0'

	def do_GET(self, body=True):
		try:
			target_url = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query).get('url', None)
			print("[INFO] target_url: "+str(target_url))
			if target_url != None:
				target_url = target_url[0]
				req_header = self.parse_headers()
				#resp = requests.get(target_url, headers=req_header, verify=False, stream=True)
				resp = requests.get(target_url, headers=req_header, verify="certs.pem", stream=True)
				print("[INFO] resp.status_code: %d " % resp.status_code)
				if resp.status_code == 404:
					self.send_response(404)
					self.send_header('Content-Type','text/html')
					self.end_headers()
					self.wfile.write("NOT FOUND".encode())
				else:
					self.send_response(resp.status_code)
					for k in resp.headers.keys():
						print("[INFO] resp.headers: [%s][%s]" % (k, resp.headers[k]) )
						self.send_header(k, resp.headers[k])
					self.end_headers()
					for chunk in resp.iter_content(chunk_size=1024):
						if chunk:
							self.wfile.write(chunk)
							self.wfile.flush()
						else:
							time.sleep(0.05)
				
			else:
				self.send_response(404)
				self.send_header('Content-Type','text/html')
				self.end_headers()
				self.wfile.write("NOT FOUND".encode())
		finally:
			pass

	def parse_headers(self):
		req_header = {}
		for line in self.headers:
			line_parts = [o.strip() for o in line.split(':', 1)]
			if len(line_parts) == 2:
				req_header[line_parts[0]] = line_parts[1]
		return self.inject_header(req_header)
    
	def inject_header(self, headers):
		headers['Referer'] = 'https://example.com/'
       
		return headers
	

if __name__ == '__main__':
	server_address = ('0.0.0.0', 8081)
	httpd = http.server.HTTPServer(server_address, ProxyHTTPRequestHandler)
	print('http server is running')
	httpd.serve_forever()

如此跑起來後,就可以用 http://localhost:8081/?url=https://exmaple.com/streaming 機制,例如 VLC 軟體直接輸入 http://localhost:8081/?url=https://exmaple.com/streaming 位置來嘗試播放。

2020年5月7日 星期四

Raspberry Pi 3 + RetroPie = 電視遊樂器 - 超任為例 @ macOS

Pi 3 + SNES

之前為了研究音控買了個 Pi 3 搭配 Google AIY Projects Voice Kit ,結果研究完就晾在那邊一年多了吧?反而音控設備已買了成品 Google Home mini 和 小愛音箱。最近無聊就想研究一下樹莓派怎樣玩遊戲,實在是已經不只一次看到什麼月光寶盒再賣,還是嘗試一下好了。

果真有個 RetroPie 就是專門做了超級多的電玩模擬器,裝下就搞定了!有幾件事要留意一下:
  • Pi 3 內建無線網卡,但安裝完卻沒法設定,連 ifconfig 都看不到
    • 解法:裝完 RetroPie 系統後,需要先設定 WI-FI Country ,才能正常設定無線網路
  • 在網路上亂找到的 ROM 檔案,擺入後卻無法被偵測或運行
    • 解法:還是裝一套 PC 版的來驗證吧 :P 有時真的是網路上的檔案格式問題,在 macOS 可以試試 OpenEMU 這套
  • 如何從 PC 傳 ROM 進入 Pi 3 + RetroPie
    • 解法:善用 RetroPie 的環境,可以把 SSH 打開,靠 SCP 或是透過 SAMBA 網路芳鄰進去也很方便
其他動作:
  • 在 https://retropie.org.uk/download/ 下載 Pi 3 作業系統
    • https://github.com/RetroPie/RetroPie-Setup/releases/download/4.6/retropie-buster-4.6-rpi2_rpi3.img.gz
  • 在 macOS command line 連續動作處理(此例 SD Card 位於 /dev/disk4,請不要隨意複製指令執行!)
    • % sudo diskutil unmountDisk /dev/disk4 % unzip retropie-buster-4.6-rpi2_rpi3.img.gz % sudo time dd bs=1m if=retropie-buster-4.6-rpi2_rpi3.img of=/dev/rdisk4 2729+0 records in 2729+0 records out 2861563904 bytes transferred in 506.080069 secs (5654370 bytes/sec) 506.10 real 0.01 user 2.08 sys % sudo diskutil unmountDisk /dev/disk4
  • 當 Pi 3 + RetroPie 啟動後,設定 Wi-fi Country 跟啟動 SSH
    • $ sudo raspi-config
      • Change User Password
      • Localisation Otions
        • Change WI-FI Country
      • Network Options
        • Wi-fi
      • Interfacing Options
        • SSH
      • Update
      • Finish
  • 更新系統以及 RetroPie 眾多資料(模擬器)
    • $ sudo apt update $ sudo apt upgrade $ sudo apt dist-upgrade $ sudo apt autoremove $ sudo apt install tmux vim

2020年5月4日 星期一

重溫超任「三國志3 中文版」

SENS 三國志3 中文版

記得第一次接觸是小學的時候,去幼稚園同學家的遊樂器材店,就這樣初次接觸三國志遊戲。下一次,則是 PC 版的三國志五了!

記得小時候搭配藍截者,有那種重返前一刻狀態的密技,就這樣用新增武將時,用耐心找到單一能力達 100 的員工 XD 此例是君主單純調配能力達到武力 100 ,其餘軍師則是花耐心找到智力 100。

就這樣,配一個君主跟三名武將,從許昌出發,而智力 100 的特色是做事不斷去煩軍師,只要軍師說 ok 就肯定 ok!透過偽書降低對方忠誠度,或是錄用對方都是軍師說好時,一定 100% 成功率的。沒想到這時把玩這款遊戲,一不小心就噴了 3 小時,更讓我想起工作上的瑣事

大概有三件事:

  • 大家特愛當中庸者,什麼都要摸一點,像是能力各個 85 甚至 95,都還不如單一項目專精 100 。單一能力達 100 時,才會進入另一個模式。
  • 單一武將兩個能力很好,不如兩個武將各一個能力好,在這種回合制上,就凸顯出兩個人的好用。例如一個人放偽書,另一個來錄用。因為有時對方身上兵權很重,第一次放偽書,可能下一回合兵權就被去除
  • 數字化,明明很普通的遊戲,卻還是被數字吸引著,養成一種無奈的耐心跟自律,規律地聽著洗腦的背景,時間就消逝了,而成就領地卻增加
這些是恰好跟工作有關,不要當英雄把責任跟任務攬在身上,一個人一天只有 24 小時!要多培養夥伴能力並珍惜單一能力技能很強的夥伴!最後,則是流量變現上持續數據化、遊戲化。