102 lines
4.1 KiB
Python
102 lines
4.1 KiB
Python
"""Start the source workstation against a loopback backend with isolated login state."""
|
|
from __future__ import annotations
|
|
|
|
import functools
|
|
import os
|
|
import socket
|
|
import sys
|
|
from dataclasses import replace
|
|
from pathlib import Path
|
|
from urllib.parse import urlsplit
|
|
|
|
import certifi
|
|
|
|
|
|
def validate_local_url(api: str) -> None:
|
|
parsed = urlsplit(api)
|
|
if (parsed.scheme != "https" or not parsed.hostname or parsed.username or parsed.password
|
|
or parsed.query or parsed.fragment):
|
|
raise ValueError("本地入口需要不带凭据的 HTTPS 地址")
|
|
addresses = {row[4][0] for row in socket.getaddrinfo(parsed.hostname, parsed.port or 443)}
|
|
if not addresses or not addresses <= {"127.0.0.1", "::1"}:
|
|
raise ValueError("本地入口仅连接解析到本机的后端")
|
|
|
|
|
|
def validate_effective_config(config, requested_api: str) -> None:
|
|
from doctor_workstation.config import normalize_api_base_url
|
|
validate_local_url(config.api_base_url)
|
|
if config.api_base_url != normalize_api_base_url(requested_api) or not config.verify_ssl:
|
|
raise ValueError("本地独立配置已改动,请在 .local-workstation/config 中核对本地服务器设置")
|
|
|
|
|
|
def local_config_type(api: str):
|
|
"""Pin this explicit local entry, including later login/config updates."""
|
|
from doctor_workstation.config import AppConfig, normalize_api_base_url
|
|
|
|
validate_local_url(api)
|
|
local_api = normalize_api_base_url(api)
|
|
|
|
class LocalAppConfig(AppConfig):
|
|
def _merge_preferences(self):
|
|
config = super()._merge_preferences()
|
|
# Use the locked login behavior with the selected local endpoint.
|
|
# Shared Qt settings and stale local preferences must not send a
|
|
# local verification session back to the production backend.
|
|
return replace(config, api_base_url=local_api, debug_mode=False,
|
|
demo_mode=False, verify_ssl=True)
|
|
|
|
return LocalAppConfig
|
|
|
|
|
|
def main() -> int:
|
|
# Select the native backend before Qt creates network objects or scans TLS
|
|
# plugins. Selecting it later can load conflicting OpenSSL DLLs on Windows.
|
|
if sys.platform == "win32":
|
|
os.environ["QT_TLS_BACKEND"] = "schannel"
|
|
root = Path(__file__).resolve().parents[1]
|
|
api = os.environ.get("DOCTOR_LOCAL_API_URL", "https://css.zhenyangtang.com.cn")
|
|
validate_local_url(api)
|
|
certificate = Path(os.environ.get(
|
|
"DOCTOR_LOCAL_CA_FILE",
|
|
"D:/phpstudy_pro/Extensions/Nginx1.15.11/conf/ssl/css.zhenyangtang.com.cn.pem",
|
|
))
|
|
private_root = root / ".local-workstation"
|
|
private_root.mkdir(parents=True, exist_ok=True)
|
|
ca_bundle = private_root / "trusted-ca.pem"
|
|
ca_bundle.write_bytes(Path(certifi.where()).read_bytes() + b"\n" + certificate.read_bytes())
|
|
os.environ.update({
|
|
"DOCTOR_CONFIG_DIR": str(private_root / "config"),
|
|
"DOCTOR_LOG_DIR": str(private_root / "logs"),
|
|
"DOCTOR_API_BASE_URL": api,
|
|
"DOCTOR_DEMO_MODE": "false",
|
|
"DOCTOR_VERIFY_SSL": "true",
|
|
"SSL_CERT_FILE": str(ca_bundle),
|
|
})
|
|
sys.path.insert(0, str(root / "src"))
|
|
# This explicit source-only entry does not edit the formal build configuration.
|
|
LocalAppConfig = local_config_type(api)
|
|
config = LocalAppConfig.load()
|
|
validate_effective_config(config, api)
|
|
config.save_preferences()
|
|
if "--check" in sys.argv:
|
|
print("Local backend: loopback HTTPS; TLS verification enabled; isolated configuration and credential namespace")
|
|
return 0
|
|
from PySide6.QtCore import QSettings
|
|
|
|
from doctor_workstation import app as workstation_app
|
|
|
|
workstation_app.AppConfig = LocalAppConfig
|
|
workstation_app.LoginWindow = functools.partial(
|
|
workstation_app.LoginWindow,
|
|
settings=QSettings("ZhenYangTang", "DoctorWorkstationLocalSource"),
|
|
)
|
|
# The normal credential service remains untouched even after a local login.
|
|
workstation_app.TokenStore = functools.partial(
|
|
workstation_app.TokenStore, service_name="zyt-doctor-workstation-local-source"
|
|
)
|
|
return workstation_app.main()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|