- assets/: sap-cli source (v2.1.0, 26 commands, 16 object types) - references/: tool constraints + error handling (self-contained) - scripts/setup.py: one-click install/config/verify - SKILL.md: full command reference + dual-platform install guide - VERSION: 2.1.0 Built from D:/Codespace/sap-cli via scripts/pack_skill.py
125 lines
3.5 KiB
Python
125 lines
3.5 KiB
Python
"""凭证管理模块。
|
||
|
||
使用 keyring 库安全存储 SAP 密码,优雅降级到 config.ini。
|
||
服务名格式: sap-cli:{host}:{client}
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import getpass
|
||
import logging
|
||
|
||
# 从独立模块导入,避免与 config 循环 import
|
||
from sapcli.password import ( # noqa: F401 – re-export
|
||
_KEYRING_AVAILABLE,
|
||
_keyring,
|
||
_keyring_mod,
|
||
_service_name,
|
||
get_password,
|
||
resolve_password,
|
||
)
|
||
|
||
logger = logging.getLogger("sapcli.auth")
|
||
|
||
|
||
def set_password(host: str, client: str, user: str, password: str) -> bool:
|
||
"""存储密码到 keyring。
|
||
|
||
Returns:
|
||
是否成功存储
|
||
"""
|
||
if not _KEYRING_AVAILABLE:
|
||
print(" ✗ keyring 库不可用,无法安全存储密码")
|
||
print(" 安装方法: pip install keyring")
|
||
return False
|
||
try:
|
||
_keyring.set_password(_service_name(host, client), user, password)
|
||
return True
|
||
except Exception as e:
|
||
print(f" ✗ 存储密码失败: {e}")
|
||
return False
|
||
|
||
|
||
def delete_password(host: str, client: str, user: str) -> bool:
|
||
"""从 keyring 删除密码。
|
||
|
||
Returns:
|
||
是否成功删除
|
||
"""
|
||
if not _KEYRING_AVAILABLE:
|
||
print(" ✗ keyring 库不可用")
|
||
return False
|
||
try:
|
||
_keyring.delete_password(_service_name(host, client), user)
|
||
return True
|
||
except _keyring_mod.errors.PasswordDeleteError:
|
||
print(" ℹ keyring 中未找到该密码")
|
||
return False
|
||
except Exception as e:
|
||
print(f" ✗ 删除密码失败: {e}")
|
||
return False
|
||
|
||
|
||
def cmd_auth_login(args: argparse.Namespace, client=None) -> None:
|
||
"""auth login: 交互式保存密码到 keyring。"""
|
||
import os
|
||
from sapcli.config import load_config
|
||
|
||
try:
|
||
cfg, _ = load_config(getattr(args, "config", None))
|
||
except Exception as e:
|
||
print(f" ✗ 无法加载配置: {e}")
|
||
return
|
||
|
||
print("=" * 60)
|
||
print(" sap-cli 密钥登录")
|
||
print("=" * 60)
|
||
print(f" 主机: {cfg.host}")
|
||
print(f" Client: {cfg.client}")
|
||
print(f" 用户: {cfg.user}")
|
||
|
||
password = getpass.getpass(" 请输入密码: ")
|
||
if not password:
|
||
print(" ✗ 密码不能为空")
|
||
return
|
||
|
||
if set_password(cfg.host, cfg.client, cfg.user, password):
|
||
print(f" ✓ 密码已安全存储到 keyring")
|
||
print(f" 服务名: {_service_name(cfg.host, cfg.client)}")
|
||
else:
|
||
print(" ✗ 密码存储失败")
|
||
|
||
|
||
def cmd_auth_logout(args: argparse.Namespace, client=None) -> None:
|
||
"""auth logout: 从 keyring 删除密码。"""
|
||
from sapcli.config import load_config
|
||
|
||
try:
|
||
cfg, _ = load_config(getattr(args, "config", None))
|
||
except Exception as e:
|
||
print(f" ✗ 无法加载配置: {e}")
|
||
return
|
||
|
||
if delete_password(cfg.host, cfg.client, cfg.user):
|
||
print(" ✓ 密码已从 keyring 删除")
|
||
else:
|
||
print(" ✗ 删除失败")
|
||
|
||
|
||
def cmd_auth_status(args: argparse.Namespace, client=None) -> None:
|
||
"""auth status: 显示 keyring 状态。"""
|
||
print("=" * 60)
|
||
print(" sap-cli 密钥状态")
|
||
print("=" * 60)
|
||
|
||
if _KEYRING_AVAILABLE:
|
||
print(f" keyring: ✓ 可用")
|
||
try:
|
||
backend = _keyring.get_keyring().__class__.__name__
|
||
print(f" 后端: {backend}")
|
||
except Exception:
|
||
logger.debug("获取 keyring 后端名称失败", exc_info=True)
|
||
else:
|
||
print(f" keyring: ✗ 不可用")
|
||
print(f" 安装方法: pip install keyring")
|