Files
NebulaShell/tools/sign_core_plugins.py
2026-04-17 23:15:15 +08:00

100 lines
2.7 KiB
Python

#!/usr/bin/env python3
"""
为 dependency 和 signature-verifier 插件签名
"""
import sys
import json
import base64
import hashlib
import time
from pathlib import Path
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
# ========== 配置 ==========
PROJECT_ROOT = Path(__file__).parent.parent
PRIVATE_KEY_FILE = PROJECT_ROOT / "data" / "signature-verifier" / "keys" / "private" / "futureoss_private.pem"
PLUGINS = ["dependency", "signature-verifier"]
def compute_plugin_hash(plugin_dir: Path) -> str:
"""计算插件目录的内容哈希"""
hasher = hashlib.sha256()
files_to_hash = []
for file_path in sorted(plugin_dir.rglob("*")):
if file_path.is_file() and file_path.name != "SIGNATURE":
rel_path = file_path.relative_to(plugin_dir)
files_to_hash.append((str(rel_path), file_path))
for rel_path, file_path in files_to_hash:
hasher.update(rel_path.encode("utf-8"))
hasher.update(file_path.read_bytes())
return hasher.hexdigest()
def sign_plugin(plugin_dir: Path):
"""为插件签名"""
# 加载私钥
print(f"加载私钥: {PRIVATE_KEY_FILE}")
private_key = serialization.load_pem_private_key(
PRIVATE_KEY_FILE.read_bytes(),
password=None,
backend=default_backend()
)
# 计算插件哈希
print(f"计算插件目录哈希: {plugin_dir.name}...")
plugin_hash = compute_plugin_hash(plugin_dir)
print(f"哈希: {plugin_hash}")
# 签名
signed_data = f"FutureOSS:{plugin_hash}".encode("utf-8")
signature = private_key.sign(
signed_data,
padding.PSS(
mgf=padding.MGF1(hashes.SHA256()),
salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA256()
)
# 写入签名文件
sig_data = {
"signature": base64.b64encode(signature).decode(),
"signer": "FutureOSS",
"algorithm": "RSA-SHA256",
"timestamp": time.time(),
"plugin_hash": plugin_hash,
"author": "FutureOSS"
}
signature_file = plugin_dir / "SIGNATURE"
signature_file.write_text(json.dumps(sig_data, indent=2))
print(f"✓ 已签名: {plugin_dir.name}")
def main():
if not PRIVATE_KEY_FILE.exists():
print(f"错误: 私钥文件不存在: {PRIVATE_KEY_FILE}")
sys.exit(1)
store_dir = PROJECT_ROOT / "store" / "@{FutureOSS}"
for plugin_name in PLUGINS:
plugin_dir = store_dir / plugin_name
if plugin_dir.exists():
sign_plugin(plugin_dir)
else:
print(f"警告: 插件目录不存在: {plugin_dir}")
print("\n完成!")
if __name__ == "__main__":
main()