- Implement tests for converter properties, ensuring correct input and output formats. - Add tests for chip parsing, covering various image, pdf_image, and pdfa chip formats. - Include tests for the isArchiveOutput and getOutputFileName functions. - Mock execFile for testing the convert function, verifying command execution and output file creation. - Ensure all chips are parseable and validate the completeness of chip categories.
129 lines
4 KiB
Python
129 lines
4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
PDF 數位簽章腳本
|
|
|
|
使用 endesive 庫對 PDF 進行數位簽章。
|
|
|
|
環境變數:
|
|
- PDF_SIGN_P12_PATH: PKCS12 憑證檔案路徑(必須)
|
|
- PDF_SIGN_P12_PASSWORD: PKCS12 憑證密碼(選用,預設為空)
|
|
- PDF_SIGN_REASON: 簽章原因(選用)
|
|
- PDF_SIGN_LOCATION: 簽章地點(選用)
|
|
- PDF_SIGN_CONTACT: 聯絡資訊(選用)
|
|
|
|
用法:
|
|
python3 pdf_sign.py <input.pdf> <output.pdf>
|
|
|
|
錯誤代碼:
|
|
0: 成功
|
|
1: 參數錯誤
|
|
2: 憑證未配置
|
|
3: 憑證讀取失敗
|
|
4: 簽章失敗
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
from datetime import datetime
|
|
|
|
def main():
|
|
# 檢查參數
|
|
if len(sys.argv) != 3:
|
|
print("用法: python3 pdf_sign.py <input.pdf> <output.pdf>", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
input_pdf = sys.argv[1]
|
|
output_pdf = sys.argv[2]
|
|
|
|
# 檢查環境變數(支援預設憑證)
|
|
p12_path = os.environ.get("PDF_SIGN_P12_PATH", "/app/certs/default.p12")
|
|
p12_password = os.environ.get("PDF_SIGN_P12_PASSWORD", "")
|
|
sign_reason = os.environ.get("PDF_SIGN_REASON", "ConvertX-CN PDF Packager")
|
|
sign_location = os.environ.get("PDF_SIGN_LOCATION", "ConvertX-CN")
|
|
sign_contact = os.environ.get("PDF_SIGN_CONTACT", "")
|
|
|
|
if not os.path.exists(p12_path):
|
|
print(f"錯誤: 憑證檔案不存在: {p12_path}", file=sys.stderr)
|
|
print("提示: Docker 環境預設使用 /app/certs/default.p12", file=sys.stderr)
|
|
print(" 如需使用自訂憑證,請設定 PDF_SIGN_P12_PATH 環境變數", file=sys.stderr)
|
|
sys.exit(2)
|
|
|
|
if not os.path.exists(input_pdf):
|
|
print(f"錯誤: 輸入檔案不存在: {input_pdf}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
try:
|
|
# 載入 endesive
|
|
from endesive.pdf import cms
|
|
from cryptography.hazmat.primitives.serialization import pkcs12
|
|
from cryptography.hazmat.backends import default_backend
|
|
|
|
# 讀取 PKCS12 憑證
|
|
print(f"[PDF Sign] 載入憑證: {p12_path}")
|
|
with open(p12_path, "rb") as f:
|
|
p12_data = f.read()
|
|
|
|
try:
|
|
private_key, certificate, additional_certs = pkcs12.load_key_and_certificates(
|
|
p12_data,
|
|
p12_password.encode() if p12_password else None,
|
|
default_backend()
|
|
)
|
|
except Exception as e:
|
|
print(f"錯誤: 無法載入憑證(密碼錯誤或格式不正確): {e}", file=sys.stderr)
|
|
sys.exit(3)
|
|
|
|
if not private_key or not certificate:
|
|
print("錯誤: 憑證中未找到私鑰或證書", file=sys.stderr)
|
|
sys.exit(3)
|
|
|
|
# 讀取 PDF
|
|
print(f"[PDF Sign] 讀取 PDF: {input_pdf}")
|
|
with open(input_pdf, "rb") as f:
|
|
pdf_data = f.read()
|
|
|
|
# 準備簽章參數
|
|
dct = {
|
|
"aligned": 0,
|
|
"sigflags": 3,
|
|
"sigflagsft": 132,
|
|
"sigpage": 0,
|
|
"sigbutton": False,
|
|
"contact": sign_contact,
|
|
"location": sign_location,
|
|
"signingdate": datetime.utcnow().strftime("%Y%m%d%H%M%S+00'00'"),
|
|
"reason": sign_reason,
|
|
}
|
|
|
|
# 執行簽章
|
|
print("[PDF Sign] 執行數位簽章...")
|
|
signed_data = cms.sign(
|
|
pdf_data,
|
|
dct,
|
|
private_key,
|
|
certificate,
|
|
additional_certs or [],
|
|
"sha256",
|
|
)
|
|
|
|
# 寫入輸出檔案
|
|
print(f"[PDF Sign] 寫入簽章 PDF: {output_pdf}")
|
|
with open(output_pdf, "wb") as f:
|
|
f.write(pdf_data)
|
|
f.write(signed_data)
|
|
|
|
print("[PDF Sign] ✅ 簽章完成")
|
|
sys.exit(0)
|
|
|
|
except ImportError as e:
|
|
print(f"錯誤: 缺少必要的 Python 庫: {e}", file=sys.stderr)
|
|
print("請確保已安裝 endesive: pip install endesive", file=sys.stderr)
|
|
sys.exit(4)
|
|
|
|
except Exception as e:
|
|
print(f"錯誤: 簽章失敗: {e}", file=sys.stderr)
|
|
sys.exit(4)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|