Repository Wiki
genshen/wssocks-plugin-ustb

运行时架构与插件集成/ustb-vpn-插件与认证流程

本文介绍 USTB VPN 插件在运行时的设置界面、认证方式选择、凭据装载以及配置持久化流程。当前可用的源码材料仅包含 VpnSettingsUI 及其相关 UI 逻辑,因此本文严格限定在已验证的实现范围内;VPN 网络请求、二维码认证后端、WebView 认证执行器和偏好设置读写函数的内部实现未在现有材料中出现。

Purpose and Scope

本页覆盖以下已由源码确认的职责:

  • 创建 VPN 认证设置窗口及其 Fyne 控件;
  • 展示并编辑强制注销、主机加密、VPN 主机、认证方式、用户名和密码;
  • 从 fyne.Preferences 加载既有 VPN 设置;
  • 在窗口关闭时保存 VPN 设置;
  • 将 UI 状态转换为 vpn.UstbVpn 运行时对象;
  • 将认证方式从 UI 文本映射为 vpn.VpnAuthMethodPasswd、vpn.VpnAuthMethodQRCode 或 vpn.VpnAuthMethodWebview。

本页不扩展到未提供源码的网络连接、认证请求协议、服务端会话管理、二维码生成与扫描、浏览器进程启动、VPN 数据面转发或插件注册机制。关于这些部分,当前材料不足以给出可靠的实现说明。

Overview

VpnSettingsUI 是一个面向桌面的 Fyne 设置控制器。它通过一组字段保存控件引用,并以 OpenVpnSettings 作为入口创建窗口。窗口打开时,代码先创建控件,再调用 loadVpnPreference 将已有偏好载入控件,最后将控件组装为表单和认证方式标签页。

认证方式在 UI 中以三个字符串选项呈现:TextVpnAuthMethodPasswd、TextVpnAuthMethodQrCode 和 TextVpnAuthMethodWebview。当运行时需要构造 vpn.UstbVpn 时,LoadSettingsValues 会读取控件状态,并通过 getAuthMethodInt 将所选字符串转换为 VPN 插件使用的整数常量。

当前实现体现出“设置窗口负责编辑,运行时对象负责承载”的边界:窗口字段保存用户交互状态,LoadSettingsValues 才把这些状态写入插件模型。密码字段使用 Fyne 的 Password: true,因此界面层会以密码输入方式显示它;源码没有表明该密码是否加密存储,不能据此推断安全存储策略。

Architecture

从已提供源码可以确认的关系如下:VpnSettingsUI 持有 Fyne 控件;OpenVpnSettings 创建窗口并调用偏好设置加载与保存函数;LoadSettingsValues 将控件映射到 vpn.UstbVpn,并为其填充 passwd.UstbVpnPasswdAuth。

由于当前响应没有提供运行时 File Reference Base URL,无法生成符合要求的仓库源码链接,也无法安全推断源文件的仓库相对路径。以下架构关系仅以文字说明,不附带未经验证的 Mermaid 代码块。

已确认的组件关系

组件已确认职责证据范围
VpnSettingsUI保存 VPN 设置控件引用,协调窗口打开和模型装载提供的源码第 12–20、22–74、94–103 行
OpenVpnSettings初始化控件、加载偏好、构造窗口、在关闭时保存第 22–74 行
loadVpnPreference向 UI 控件加载偏好值第 39–40 行调用;实现未提供
saveVPNPreference在窗口关闭时保存 UI 值第 69–72 行调用;实现未提供
loadFilePicker打开文件选择对话框并写入浏览器路径第 76–92 行
getAuthMethodInt将选中的认证方式字符串转换为 VPN 常量第 105–114 行
vpn.UstbVpn接收运行时 VPN 设置第 94–103 行使用;类型定义未提供
passwd.UstbVpnPasswdAuth接收用户名和密码第 99–102 行使用;类型定义未提供

设置窗口生命周期

1. 控件初始化

OpenVpnSettings 首先创建两个默认选中的复选框:uiVpnForceLogout 和 uiVpnHostEncrypt。VPN 主机输入框的默认文本是 n.ustb.edu.cn,用户名和密码为空,密码控件设置为密码模式。

认证方式通过 widget.NewRadioGroup 创建,并包含密码、二维码和 WebView 三个选项。其回调函数当前只有 todo: 注释,没有实现选择变化后的动态行为。因此,认证方式切换不会在已提供代码中触发额外逻辑。

浏览器路径输入框随后被创建并禁用。源码只展示了它作为 WebView 标签页中的路径展示控件,以及由文件选择按钮填充路径;没有展示启用该输入框的逻辑。

2. 偏好加载

所有控件创建完成后,OpenVpnSettings 调用 loadVpnPreference,传入偏好对象和全部 VPN 控件。这表明加载逻辑位于独立函数中,而不是散落在窗口布局代码中。由于该函数实现未提供,默认值与已保存值之间的覆盖规则只能确认“调用发生”,不能确认具体优先级或缺省策略。

3. 窗口和布局

窗口标题为 VPN Auth Settings,内容由垂直容器组成。顶部表单包含强制注销、主机加密、VPN 主机和认证方式;其后是分隔线和三个标签页:

  • Password Auth:用户名和密码表单;
  • QR Code Auth:目前仅显示 World! 标签;
  • Webview Auth:浏览器路径选择按钮和禁用的路径输入框。

窗口尺寸设置为宽 400、高度 0。源码没有说明 Fyne 对高度 0 的具体布局结果,因此不应将其解释为固定高度或自动高度策略。

4. 窗口关闭和保存

窗口通过 SetOnClosed 注册关闭回调。回调调用 saveVPNPreference,传入与加载阶段相同的偏好对象和控件集合。由此可确认,保存时机是窗口关闭,而不是每次字段变化时实时保存。

这一设计减少了频繁写入偏好的次数,但也意味着在窗口异常退出或应用未触发关闭回调时,源码没有显示额外的保存保障机制。

认证方式映射

getAuthMethodInt 根据 RadioGroup.Selected 的值进行映射:

UI 选项输出常量
TextVpnAuthMethodPasswdvpn.VpnAuthMethodPasswd
TextVpnAuthMethodQrCodevpn.VpnAuthMethodQRCode
其他值,包括 WebView 选项和空值vpn.VpnAuthMethodWebview

实现使用的是“两个显式分支加兜底”的策略,而不是显式列出 WebView 分支。因此,任何不是密码或二维码文本的值都会被视为 WebView。这使得函数对未知值具有确定结果,但也可能掩盖文本常量拼写错误。当前源码没有额外的校验或错误返回值。

运行时模型装载

LoadSettingsValues 将 UI 当前值写入传入的 *vpn.UstbVpn:

  • ForceLogout 来自强制注销复选框;
  • HostEncrypt 来自主机加密复选框;
  • TargetVpn 来自 VPN 主机输入框;
  • AuthMethod 来自 getAuthMethodInt;
  • PasswdAuth.Username 和 PasswdAuth.Password 来自用户名、密码输入框。

值得注意的是,方法只写入 PasswdAuth,没有在该方法中写入浏览器路径,也没有为二维码或 WebView 认证创建其他认证对象。结合当前源码,只能确认密码认证数据的装载路径;其他认证方式的运行时数据流尚未实现或不在提供材料中。

文件选择流程

loadFilePicker 返回一个按钮。用户点击按钮后,代码创建 dialog.NewFileOpen,显示文件打开对话框;回调首先检查错误和空 reader,随后读取 reader.URI().Path() 并写入 pathContainer。

该流程只负责把所选 URI 的路径展示到输入框。源码没有对扩展名、文件类型、路径存在性或浏览器可执行性进行验证,也没有显示启动 Chrome、Edge 或 Chromium 的代码。按钮标题提到这些浏览器,但不能据此推断实际支持的浏览器校验逻辑。

Core Flow

从现有实现可以还原出以下顺序:

  1. 调用方创建或持有 VpnSettingsUI;
  2. 调用 OpenVpnSettings;
  3. 创建控件并设置默认值;
  4. 调用 loadVpnPreference 加载已保存设置;
  5. 创建 VPN Auth Settings 窗口并显示;
  6. 用户编辑字段,或通过文件选择器填充浏览器路径;
  7. 窗口关闭时调用 saveVPNPreference;
  8. 需要构造 VPN 运行时对象时,调用方使用 LoadSettingsValues;
  9. LoadSettingsValues 将控件状态写入 vpn.UstbVpn。

源码没有展示 OpenVpnSettings 与 LoadSettingsValues 之间的直接调用关系,因此不能断言关闭窗口后必然立即创建 VPN 对象。二者是由 VpnSettingsUI 提供的两个独立操作入口。

Usage Examples

当前提供的材料包含实现代码,但没有提供可安全引用的实际仓库相对路径和 File Reference Base URL。根据“代码示例必须带真实源码链接”的约束,本页不复制代码块,也不伪造链接。可验证的调用行为已在“设置窗口生命周期”“认证方式映射”和“运行时模型装载”章节中以逐步文字形式说明。

Configuration Options

设置UI 类型当前源码中的默认值写入位置备注
强制注销widget.Checktruevpn.UstbVpn.ForceLogout默认由 newCheckbox("", true, nil) 创建
主机加密widget.Checktruevpn.UstbVpn.HostEncrypt默认由 newCheckbox("", true, nil) 创建
VPN 主机widget.Entryn.ustb.edu.cnvpn.UstbVpn.TargetVpn可编辑文本
用户名widget.Entry空字符串vpn.UstbVpn.PasswdAuth.Username密码认证页使用
密码widget.Entry空字符串vpn.UstbVpn.PasswdAuth.PasswordPassword: true
认证方式widget.RadioGroup未在控件创建处显式设置vpn.UstbVpn.AuthMethod由偏好加载函数或用户选择决定
浏览器路径widget.Entry空字符串当前提供的方法未写入 vpn.UstbVpn初始禁用,由文件选择器填充

loadVpnPreference 和 saveVPNPreference 的具体偏好键名、序列化方式、缺省值覆盖规则和敏感信息处理方式未提供,不能进一步补充配置参考。

API Reference

(*VpnSettingsUI).OpenVpnSettings(wssApp *fyne.App, pref fyne.Preferences)

创建并显示 VPN 认证设置窗口。

参数:

  • wssApp *fyne.App:用于创建新窗口的 Fyne 应用指针。源码通过 (*wssApp).NewWindow 创建窗口。
  • pref fyne.Preferences:传递给 loadVpnPreference 和 saveVPNPreference 的偏好对象。

返回值: 无。

已确认行为: 初始化 VPN 设置控件,加载偏好,创建布局,注册窗口关闭保存回调并显示窗口。

异常与错误: 源码中没有显式错误返回,也没有展示对空应用指针的检查。

(*VpnSettingsUI).LoadSettingsValues(values *vpn.UstbVpn)

将 UI 控件当前值复制到 vpn.UstbVpn 实例。

参数:

  • values *vpn.UstbVpn:接收 VPN 设置的指针。

返回值: 无。

已确认写入: ForceLogout、HostEncrypt、TargetVpn、AuthMethod 和 PasswdAuth 的用户名密码。

异常与错误: 源码没有显式错误返回或空指针检查。调用前必须确保 VpnSettingsUI 的控件已经由 OpenVpnSettings 初始化,并且 values 可写。

loadFilePicker(win fyne.Window, pathContainer *widget.Entry) *widget.Button

创建一个用于选择浏览器文件的 Fyne 按钮。

参数:

  • win fyne.Window:传给文件打开对话框的父窗口。
  • pathContainer *widget.Entry:接收所选 URI 路径的输入框。

返回值: 配置完成的 *widget.Button。

已确认行为: 点击后显示文件打开对话框;成功获得非空 reader 时,将 reader.URI().Path() 写入 pathContainer。

异常与边界: 文件选择错误或取消选择时直接返回,不更新路径。源码没有检查 pathContainer 是否为空。

getAuthMethodInt(uiVpnAuthMethod *widget.RadioGroup) int

将认证方式单选框的字符串选择映射为 VPN 插件认证方式整数。

参数:

  • uiVpnAuthMethod *widget.RadioGroup:提供 Selected 文本的单选框。

返回值: VPN 认证方式整数常量。

映射规则: 密码映射为 vpn.VpnAuthMethodPasswd,二维码映射为 vpn.VpnAuthMethodQRCode,其余值映射为 vpn.VpnAuthMethodWebview。

Failure Modes and Edge Cases

未初始化控件

LoadSettingsValues 直接访问多个 UI 字段。如果它在 OpenVpnSettings 完成控件初始化前调用,源码没有保护措施。具体表现取决于未初始化指针的访问结果;调用生命周期应由上层保证。

空或未知认证方式

getAuthMethodInt 对空字符串和所有未知字符串采用 WebView 兜底。该行为是源码明确实现的结果,但不是错误检测机制。若认证方式文本常量发生变化,可能会静默选择 WebView。

文件选择取消或失败

文件对话框回调显式处理错误和 nil reader,并直接返回。已有路径不会在这两种情况下被清空,因为只有成功读取 URI 后才调用 SetText。

浏览器路径不可用

路径输入框在创建后被禁用。当前材料没有显示启用路径输入框、检查路径或使用路径启动浏览器的逻辑,因此浏览器认证链路的可用性无法从此组件确认。

保存时机

偏好保存只注册在 SetOnClosed 回调中。源码没有展示实时保存、取消按钮、脏状态检测或关闭失败处理。

敏感信息

密码被写入 vpn.UstbVpn.PasswdAuth.Password,并传给偏好加载/保存相关流程的 UI 控件集合。源码材料没有提供 saveVPNPreference 的实现,不能判断密码是否明文保存、加密保存或根本不持久化。运维和安全评估必须继续检查该函数实现。

Extension Points and Implementation Gaps

当前可见的扩展点主要是认证方式回调:NewRadioGroup 接收了一个值变化回调,但其主体仍是 todo:。实现者可以在该回调中加入标签页切换、字段启用状态调整或认证参数校验,但这些行为目前并未发生。

二维码标签页仍显示静态 World!,说明二维码认证 UI 尚未在此文件中实现。WebView 标签页提供文件选择器和路径展示,但路径输入框被禁用,且没有后续浏览器执行逻辑。若要补齐这两种认证方式,需要先确认 vpn.UstbVpn 的数据模型和插件服务接口;这些定义不在现有材料中。

Tests and Verification Status

提供的源码材料中没有测试文件或测试函数,因此无法列出已有测试覆盖范围。可以确认的验证点仅限于静态代码行为:默认主机值为 n.ustb.edu.cn,两个复选框初始选中,密码输入框启用密码模式,关闭窗口会调用保存函数,文件选择成功后写入 URI 路径,以及认证方式映射采用密码、二维码、WebView 三分支规则。

当前运行上下文未提供可用的源码文件引用基地址、仓库相对路径或同一目录下的相关目录信息,因此不添加猜测性的源码链接或文档链接。若要继续完善本页,应补充并读取以下实现:loadVpnPreference、saveVPNPreference、vpn.UstbVpn、vpn.VpnAuthMethod*、passwd.UstbVpnPasswdAuth,以及 VPN 插件注册和认证执行入口。

Sources

(1 files)