91 lines
3.1 KiB
Python
91 lines
3.1 KiB
Python
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
|
||
DIRECTORY = Path(__file__).resolve().parent
|
||
EXAMPLE_NAME = "用户名密码ip.example.txt"
|
||
PRIVATE_NAME = "用户名密码ip.txt"
|
||
REQUIRED_KEYS = (
|
||
"设备",
|
||
"主机名",
|
||
"用户名",
|
||
"密码",
|
||
"IP",
|
||
"SSH",
|
||
"镜像默认用户名",
|
||
"镜像默认账户密码",
|
||
"镜像默认WiFi SSID",
|
||
"镜像默认WiFi密码",
|
||
)
|
||
PLACEHOLDER_MARKERS = ("<", ">", "示例", "example", "请填写", "待填写")
|
||
|
||
|
||
class CredentialPreparationError(RuntimeError):
|
||
"""A safe, user-actionable credential preparation failure."""
|
||
|
||
|
||
def _parse_fields(path: Path) -> dict[str, str]:
|
||
fields: dict[str, str] = {}
|
||
for raw_line in path.read_text(encoding="utf-8").splitlines():
|
||
line = raw_line.strip()
|
||
if not line or line.startswith("#"):
|
||
continue
|
||
separator = ":" if ":" in line else ":" if ":" in line else None
|
||
if separator is None:
|
||
raise CredentialPreparationError("凭据文件含有无法识别的非注释行。")
|
||
key, value = (part.strip() for part in line.split(separator, 1))
|
||
if not key or key in fields:
|
||
raise CredentialPreparationError("凭据文件含有空字段名或重复字段。")
|
||
fields[key] = value
|
||
return fields
|
||
|
||
|
||
def ensure_credentials(directory: Path = DIRECTORY) -> bool:
|
||
example_path = directory / EXAMPLE_NAME
|
||
private_path = directory / PRIVATE_NAME
|
||
if not example_path.is_file():
|
||
raise CredentialPreparationError(f"缺少示例文件:{EXAMPLE_NAME}")
|
||
|
||
if not private_path.exists():
|
||
payload = example_path.read_bytes()
|
||
try:
|
||
with private_path.open("xb") as stream:
|
||
stream.write(payload)
|
||
except FileExistsError:
|
||
pass
|
||
print(f"已创建私有凭据副本:测试相关资料/核桃派的用户名和密码和ip/{PRIVATE_NAME}")
|
||
print("请填写全部字段后重新运行本检查;在此之前不要继续 SSH、部署或镜像定制。")
|
||
return False
|
||
if not private_path.is_file():
|
||
raise CredentialPreparationError(f"私有凭据路径不是普通文件:{PRIVATE_NAME}")
|
||
|
||
fields = _parse_fields(private_path)
|
||
missing = [key for key in REQUIRED_KEYS if key not in fields]
|
||
if missing:
|
||
raise CredentialPreparationError("凭据文件缺少字段:" + "、".join(missing))
|
||
unfinished = [
|
||
key
|
||
for key in REQUIRED_KEYS
|
||
if not fields[key]
|
||
or any(marker.casefold() in fields[key].casefold() for marker in PLACEHOLDER_MARKERS)
|
||
]
|
||
if unfinished:
|
||
raise CredentialPreparationError("凭据文件仍有未填写字段:" + "、".join(unfinished))
|
||
|
||
print("私有凭据文件可用;未输出任何凭据值。")
|
||
return True
|
||
|
||
|
||
def main() -> int:
|
||
try:
|
||
return 0 if ensure_credentials() else 2
|
||
except (CredentialPreparationError, OSError, UnicodeError) as error:
|
||
print(f"凭据检查未通过:{error}", file=sys.stderr)
|
||
return 2
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|