新增简易的8080面板😊

This commit is contained in:
Falck
2026-04-17 23:15:15 +08:00
parent c38d2f66d1
commit 9d19d09821
465 changed files with 9235 additions and 35285 deletions

View File

@@ -0,0 +1,99 @@
#!/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()

102
tools/sign_plugin_loader.py Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""
为 plugin-loader 插件签名
"""
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"
PLUGIN_DIR = PROJECT_ROOT / "store" / "@{FutureOSS}" / "plugin-loader"
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():
"""为插件签名"""
# 加载私钥
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_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"\n✓ 签名成功!")
print(f" 插件: {PLUGIN_DIR.name}")
print(f" 签名文件: {signature_file}")
print(f" 算法: RSA-SHA256")
print(f" 时间戳: {time.strftime('%Y-%m-%d %H:%M:%S')}")
if __name__ == "__main__":
try:
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
except ImportError:
print("错误: 未安装 cryptography 库")
print("运行: pip install cryptography")
sys.exit(1)
if not PLUGIN_DIR.exists():
print(f"错误: 插件目录不存在: {PLUGIN_DIR}")
sys.exit(1)
if not PRIVATE_KEY_FILE.exists():
print(f"错误: 私钥文件不存在: {PRIVATE_KEY_FILE}")
sys.exit(1)
sign_plugin()

193
tools/sign_plugins.py Normal file
View File

@@ -0,0 +1,193 @@
#!/usr/bin/env python3
"""
密钥生成与插件签名工具
- 生成 Falck 官方密钥对
- 为所有官方插件签名
"""
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, rsa
from cryptography.hazmat.backends import default_backend
# ========== 配置 ==========
PROJECT_ROOT = Path(__file__).parent.parent # 修复tools 的上级目录
KEY_DIR = PROJECT_ROOT / "data" / "signature-verifier" / "keys"
STORE_DIR = PROJECT_ROOT / "store"
# 官方作者目录
OFFICIAL_AUTHORS = ["FutureOSS", "Falck"]
def generate_keypair(author: str):
"""生成 4096 位 RSA 密钥对"""
print(f"\n{'='*60}")
print(f"生成 {author} 的密钥对...")
print(f"{'='*60}")
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
backend=default_backend()
)
public_key = private_key.public_key()
# 保存私钥
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
priv_dir = KEY_DIR / "private"
priv_dir.mkdir(parents=True, exist_ok=True)
priv_file = priv_dir / f"{author.lower()}_private.pem"
priv_file.write_bytes(private_pem)
print(f"私钥已保存: {priv_file}")
# 保存公钥
public_pem = public_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
pub_dir = KEY_DIR / "public"
pub_dir.mkdir(parents=True, exist_ok=True)
pub_file = pub_dir / f"{author}.pem"
pub_file.write_bytes(public_pem)
print(f"公钥已保存: {pub_file}")
# 显示公钥(用于嵌入代码)
print(f"\n--- 公钥 PEM (用于嵌入 main.py) ---")
print(public_pem.decode())
print(f"--- END ---\n")
return private_key, public_key
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, private_key, signer_name: str, author: str):
"""为插件生成签名"""
plugin_hash = compute_plugin_hash(plugin_dir)
# 签名
signed_data = f"{author}:{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": signer_name,
"algorithm": "RSA-SHA256",
"timestamp": time.time(),
"plugin_hash": plugin_hash,
"author": author
}
signature_file = plugin_dir / "SIGNATURE"
signature_file.write_text(json.dumps(sig_data, indent=2))
print(f" ✓ 已签名: {plugin_dir.name} (哈希: {plugin_hash[:16]}...)")
def sign_all_plugins(private_key):
"""为所有官方插件签名"""
for author in OFFICIAL_AUTHORS:
author_dir = STORE_DIR / f"@{{{author}}}"
if not author_dir.exists():
print(f"\n警告: 作者目录不存在: {author_dir}")
continue
print(f"\n{'='*60}")
print(f"为 @{{{author}}} 的插件签名...")
print(f"{'='*60}")
count = 0
for plugin_dir in sorted(author_dir.iterdir()):
if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists():
sign_plugin(plugin_dir, private_key, author, author)
count += 1
print(f"\n完成: 已签名 {count} 个 @{author} 插件")
def main():
print("="*60)
print("FutureOSS 插件签名工具")
print("="*60)
# 检查 cryptography
try:
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.hazmat.backends import default_backend
except ImportError:
print("错误: 未安装 cryptography 库")
print("运行: pip install cryptography")
sys.exit(1)
# 步骤 1: 生成密钥对
print("\n步骤 1: 生成 Falck 官方密钥对...")
falck_priv, falck_pub = generate_keypair("Falck")
print("\n步骤 1b: 生成 FutureOSS 官方密钥对...")
foss_priv, foss_pub = generate_keypair("FutureOSS")
# 步骤 2: 为所有官方插件签名(使用对应的密钥)
print("\n步骤 2: 为所有官方插件签名...")
# Falck 的插件用 Falck 密钥签名
falck_dir = STORE_DIR / "@{Falck}"
if falck_dir.exists():
print(f"\n{'='*60}")
print("为 @{Falck} 的插件使用 Falck 密钥签名...")
print(f"{'='*60}")
for plugin_dir in sorted(falck_dir.iterdir()):
if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists():
sign_plugin(plugin_dir, falck_priv, "Falck", "Falck")
# FutureOSS 的插件用 FutureOSS 密钥签名
foss_dir = STORE_DIR / "@{FutureOSS}"
if foss_dir.exists():
print(f"\n{'='*60}")
print("为 @{FutureOSS} 的插件使用 FutureOSS 密钥签名...")
print(f"{'='*60}")
for plugin_dir in sorted(foss_dir.iterdir()):
if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists():
sign_plugin(plugin_dir, foss_priv, "FutureOSS", "FutureOSS")
print("\n" + "="*60)
print("全部完成!")
print("="*60)
print(f"\n密钥位置: {KEY_DIR}")
print("请将公钥嵌入 signature-verifier/main.py 的 FALCK_PUBLIC_KEY_PEM 变量")
print("并妥善保管私钥,不要提交到版本控制系统!")
if __name__ == "__main__":
main()

102
tools/sign_single_plugin.py Normal file
View File

@@ -0,0 +1,102 @@
#!/usr/bin/env python3
"""
为单个插件签名
"""
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"
PLUGIN_DIR = PROJECT_ROOT / "store" / "@{FutureOSS}" / "log-terminal"
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():
"""为插件签名"""
# 加载私钥
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_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"\n✓ 签名成功!")
print(f" 插件: {PLUGIN_DIR.name}")
print(f" 签名文件: {signature_file}")
print(f" 算法: RSA-SHA256")
print(f" 时间戳: {time.strftime('%Y-%m-%d %H:%M:%S')}")
if __name__ == "__main__":
try:
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
except ImportError:
print("错误: 未安装 cryptography 库")
print("运行: pip install cryptography")
sys.exit(1)
if not PLUGIN_DIR.exists():
print(f"错误: 插件目录不存在: {PLUGIN_DIR}")
sys.exit(1)
if not PRIVATE_KEY_FILE.exists():
print(f"错误: 私钥文件不存在: {PRIVATE_KEY_FILE}")
sys.exit(1)
sign_plugin()

199
tools/test_signature.py Normal file
View File

@@ -0,0 +1,199 @@
#!/usr/bin/env python3
"""
签名验证测试脚本
测试签名验证功能是否正常工作
"""
import sys
import json
import base64
import hashlib
from pathlib import Path
# 添加项目路径
sys.path.insert(0, str(Path(__file__).parent.parent))
sys.path.insert(0, str(Path(__file__).parent.parent / "store/@{FutureOSS}/signature-verifier"))
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
from cryptography.exceptions import InvalidSignature
# 导入签名验证插件
from main import SignatureVerifier, SignatureSigner
def test_verify_official_plugins():
"""测试验证所有已签名的官方插件"""
print("="*60)
print("测试 1: 验证所有官方插件签名")
print("="*60)
store_dir = Path(__file__).parent.parent / "store"
verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys")
authors = ["FutureOSS", "Falck"]
total = 0
passed = 0
failed = 0
for author in authors:
author_dir = store_dir / f"@{{{author}}}"
if not author_dir.exists():
continue
print(f"\n--- @{author} ---")
for plugin_dir in sorted(author_dir.iterdir()):
if plugin_dir.is_dir() and (plugin_dir / "manifest.json").exists():
total += 1
valid, msg = verifier.verify_plugin(plugin_dir, author)
status = "✅ 通过" if valid else "❌ 失败"
print(f" {status}: {plugin_dir.name} - {msg}")
if valid:
passed += 1
else:
failed += 1
print(f"\n{'='*60}")
print(f"结果: {passed}/{total} 通过, {failed} 失败")
print(f"{'='*60}")
return failed == 0
def test_tamper_detection():
"""测试篡改检测"""
print("\n" + "="*60)
print("测试 2: 篡改检测")
print("="*60)
store_dir = Path(__file__).parent.parent / "store"
verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys")
# 选择一个测试插件
test_plugin = store_dir / "@{FutureOSS}" / "dashboard"
if not test_plugin.exists():
print("跳过: dashboard 插件不存在")
return True
# 验证原始签名
valid_before, msg_before = verifier.verify_plugin(test_plugin, "FutureOSS")
print(f"\n篡改前: {'✅ 有效' if valid_before else '❌ 无效'} - {msg_before}")
if not valid_before:
print("警告: 原始签名已无效,跳过篡改测试")
return False
# 创建一个临时篡改文件
tamper_file = test_plugin / "__tamper_test__.tmp"
tamper_file.write_text("tampered content")
# 验证篡改后的签名
valid_after, msg_after = verifier.verify_plugin(test_plugin, "FutureOSS")
print(f"篡改后: {'✅ 有效' if valid_after else '❌ 无效'} - {msg_after}")
# 清理
tamper_file.unlink()
# 再次验证应该恢复有效
valid_clean, msg_clean = verifier.verify_plugin(test_plugin, "FutureOSS")
print(f"清理后: {'✅ 有效' if valid_clean else '❌ 无效'} - {msg_clean}")
# 预期:篡改后无效,清理后有效
success = not valid_after and valid_clean
print(f"\n{'='*60}")
print(f"篡改检测: {'✅ 成功' if success else '❌ 失败'}")
print(f"{'='*60}")
return success
def test_missing_signature():
"""测试缺失签名文件"""
print("\n" + "="*60)
print("测试 3: 缺失签名检测")
print("="*60)
store_dir = Path(__file__).parent.parent / "store"
verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys")
# 选择一个插件并临时移除签名
test_plugin = store_dir / "@{FutureOSS}" / "json-codec"
if not test_plugin.exists():
print("跳过: json-codec 插件不存在")
return True
sig_file = test_plugin / "SIGNATURE"
if not sig_file.exists():
print("跳过: json-codec 没有签名文件")
return True
# 备份签名
backup = sig_file.read_text()
sig_file.unlink()
# 验证
valid, msg = verifier.verify_plugin(test_plugin, "FutureOSS")
print(f"无签名: {'✅ 有效' if valid else '❌ 无效'} - {msg}")
# 恢复
sig_file.write_text(backup)
valid_restored, msg_restored = verifier.verify_plugin(test_plugin, "FutureOSS")
print(f"恢复后: {'✅ 有效' if valid_restored else '❌ 无效'} - {msg_restored}")
success = not valid and valid_restored
print(f"\n{'='*60}")
print(f"缺失签名检测: {'✅ 成功' if success else '❌ 失败'}")
print(f"{'='*60}")
return success
def test_official_check():
"""测试 is_official_plugin 方法"""
print("\n" + "="*60)
print("测试 4: 官方插件识别")
print("="*60)
store_dir = Path(__file__).parent.parent / "store"
verifier = SignatureVerifier(key_dir="./data/signature-verifier/keys")
# 测试官方插件
official_plugin = store_dir / "@{FutureOSS}" / "dashboard"
is_official = verifier.is_official_plugin(official_plugin)
print(f"dashboard 是官方插件: {'✅ 是' if is_official else '❌ 否'}")
success = is_official
print(f"\n{'='*60}")
print(f"官方插件识别: {'✅ 成功' if success else '❌ 失败'}")
print(f"{'='*60}")
return success
def main():
print("FutureOSS 签名验证系统测试")
print("="*60)
results = []
results.append(("官方插件验证", test_verify_official_plugins()))
results.append(("篡改检测", test_tamper_detection()))
results.append(("缺失签名检测", test_missing_signature()))
results.append(("官方插件识别", test_official_check()))
print("\n" + "="*60)
print("测试总结")
print("="*60)
for name, passed in results:
status = "✅ 通过" if passed else "❌ 失败"
print(f" {status}: {name}")
all_passed = all(r[1] for r in results)
print(f"\n{'='*60}")
print(f"总体结果: {'✅ 全部通过' if all_passed else '❌ 有失败'}")
print(f"{'='*60}")
return 0 if all_passed else 1
if __name__ == "__main__":
sys.exit(main())