iOS 移动客户端

ServerBee 原生 iOS 配套应用,支持二维码配对、推送通知和实时监控。

ServerBee 提供原生 iOS 配套应用,把服务器监控带到你的手机:实时指标、告警历史,以及随时随地管理服务器。目前支持已验证通知注册和定时任务最终结果通知,成功通知需单独启用,现已支持通过 Server 确认的移动订阅接收加密告警触发和恢复通知,管理员安全规则通知沿用同一已验证的加密投递链路。

获取方式

本仓库目前没有发布可直接安装的 iOS 构建,也没有提供 App Store/TestFlight 获取链接。下方流程适用于你从 ServerBee 运维方取得的构建,或自行从源码构建的应用。自行构建时先安装 Xcode 与 XcodeGen,然后执行:

cd apps/ios
xcodegen generate
open ServerBee.xcodeproj

从源码构建需要自己的 Apple Development Team。官方应用的设计由发布者运营的独立 Relay 保管 APNs 凭证,官方应用用户和自托管 Server 运维者无需持有发布者的密钥。本仓库尚未分发该签名应用,本地构建不能证明 真实 APNs 投递。

功能特性

  • 二维码配对 -- 扫描 Web 应用中的二维码即可即时认证,无需手动输入 Token
  • 已验证通知设置 -- 显式授权、订阅设置与 已认证安装注册,以及管理员所有者的任务最终结果通知,成功通知需单独启用,以及无需通知组的加密告警触发、恢复和管理员安全规则通知
  • 实时指标 -- 通过 WebSocket 传输的实时服务器状态、CPU、内存、磁盘和网络指标
  • 告警历史 -- 查看近期告警及其状态(触发/已解决)和详细信息
  • 安全认证 -- 基于 Bearer Token 的认证,支持自动刷新(15 分钟访问令牌,30 天刷新令牌)

系统要求

  • iOS 17.0 或更高版本
  • 启用移动认证的 ServerBee 服务器实例(v0.8.0+)
  • 已验证通知设置需要:配置 HTTPS Push Relay,并使用正确签名、正确签名的实体设备

设备配对

1. 启用移动认证(服务端)

在 v0.8.0+ 中,移动认证默认启用。除非需要调整令牌有效期,否则无需额外配置。

可选配置(server.toml):

[mobile]
access_ttl = 900      # 访问令牌有效期(秒),默认 15 分钟
refresh_ttl = 2592000 # 刷新令牌有效期(秒),默认 30 天

2. 从 Web 应用开始配对

  1. 登录你的 ServerBee Web 应用
  2. 进入 设置 → 移动设备
  3. 点击 配对新设备
  4. 显示一个 5 分钟有效期的二维码

3. 使用 iOS 应用扫描

  1. 打开 ServerBee iOS 应用
  2. 在欢迎屏幕点击 扫描二维码
  3. 将相机对准 Web 应用中显示的二维码
  4. 应用将自动认证并显示你的服务器列表

恢复过期登录

如果应用无法刷新或安全退出旧登录,会保留原 Server 与账户并打开会话恢复页。在同一 Server 的 Web 应用登录原账户,从设置 → 移动设备生成新的配对二维码,再在 iOS 恢复页点击扫描二维码恢复会话。此扫描只验证清理旧会话的权限,不会建立新的登录。如果页面列出会话,请根据设备名和时间选择原会话,并确认退出所选会话。应用会保留准确的选择用于重试,其他设备和较新的登录保持不变。确认清理完成后,再通过普通二维码配对重新登录。重启或恢复授权过期后,请扫描新的二维码。使用密码的账户也可选择密码及 TOTP 恢复。

管理已配对设备

查看已配对设备

在 Web 应用中,进入 设置 → 移动设备 查看所有已配对的 iOS 设备:

  • 设备名称(如 "iPhone 15 Pro")
  • 配对日期和时间
  • 最后活跃时间戳

撤销访问权限

要移除设备的访问权限:

  1. 在 移动设备 列表中找到要移除的设备
  2. 点击 撤销 按钮
  3. 确认操作

该设备将立即登出,其所有令牌将被作废。

已验证通知设置

登录不会申请通知权限。打开 设置 → 通知,选择订阅后点击 启用通知。Server 确认保存的偏好后,iOS 才申请权限。安全与任务订阅仅限管理员,成功任务通知默认关闭,有任务访问权限的接收者可以单独启用。

通知页面使用 Server 确认的权限,即使本地缓存的登录角色已经过期。管理员被降权后,保存订阅或关闭通知会清除不再允许的安全与任务类别。保存失败不会替换已确认的偏好。

回到应用、网络重连或注册恢复后,订阅保存失败仍会显示。页面保留尚未确认的选择,直到保存成功,或 Server 在更新的设置版本中确认已提交的合法偏好。仅注册成功不能确认这些选择。

页面分别显示系统权限与 Server 注册状态。保存失败会保留上次确认的偏好并显示错误。重试通知设置可重试验证,打开系统通知设置可调整 iOS 权限。应用会在启动、回到前台和网络恢复时核对注册,不会因登录而弹出权限请求。

开启“告警触发与恢复”可接收告警状态变化。 使用发送测试通知仅测试当前认证安装。Server 加密消息,公开 Relay 将密文转发给 APNs,Notification Service Extension 解密并本地化内容。页面分别报告服务商接受和设备展示,展示需在真机观察。点击有效测试通知会打开当前账户,旧账户、旧部署或无效消息不能触发导航。任务最终失败和已启用的成功通知使用相同的加密流程,管理员也可启用安全规则通知。

测试通知先进入 Server 的持久加密队列。等待发送表示已在本地排队;可重试表示尚未确认提供商接受,将再次尝试;已接受表示收到 APNs 提供商回执;永久失败停止重试;已过期表示通知已到达创建后 30 分钟的期限。重试和 Server 重启不会延长期限。页面会刷新当前测试状态,响应丢失后重试会保留同一测试标识。网络结果不明确时可能重复发送,接受或重试均不保证只展示一次。

每次发送前,Server 都会检查账户、当前角色、移动会话、订阅和注册版本。重复注册相同令牌、环境、内容密钥和部署时保留注册版本、密文与原始重试期限;真实身份变化仍会隔离旧任务。关闭通知、退出登录、撤销设备或账户、会话过期、替换注册会阻止后续符合条件的发送。已在发送中或已被 APNs 接受的通知无法撤回。队列保存加密内容,不会另存明文通知历史。终态会清除密文,不含凭证的发送回执会保留,以避免重复入队重新开始有效期。

当前安装测试 API

POST /api/mobile/push/test 必须携带 expected_revision 和客户端保留的 UUID event_id。接口将密文持久入队,返回等待发送状态和 presentation=unobserved。响应结果不明时使用同一 UUID 和版本重试;GET /api/mobile/push/test/{event_id} 仅读取当前认证安装及登录的回执。主动创建新测试时使用新 UUID,状态恢复不重新计算原始 30 分钟期限。

告警触发与恢复

Server 分别为当前符合条件的已订阅安装排队发送加密通知,无需外部通知组。启用规则保留原有覆盖范围、维护窗口、触发模式与通知抑制行为。恢复沿用现有评估器的状态转换行为,包括在维护期间恢复。派送前取消订阅会阻止该安装后续符合条件的发送。外部渠道继续使用自己的通知组;已迁移安装不会恢复旧 APNs 投递。

点击会等待登录恢复,并校验当前部署、账户与安装身份。告警目标包含规则、Server、事件维度和触发周期。已删除的告警或被覆盖的周期会显示“未找到告警”,并提供“返回告警列表”,不会打开较新的周期。扩展以英语或简体中文显示触发与恢复文本;解密失败时仅显示通用文本,不提供导航目标。

排队投递和扩展展示在创建后 30 分钟到期。通知中心中已展示的通知超过该期限后被点击,仍会验证完整目标并向 Server 请求当前详情。投递期限不授予访问权限,登录身份改变时拒绝导航,告警已删除或不可用时使用同一安全回退。

任务最终失败

管理员可启用任务最终失败订阅。手动启动的定时任务通知发起者,自动运行通知创建者,不会通知其他订阅管理员。所有目标完成最终尝试后,每个符合条件的安装收到一个逻辑汇总。中间失败保持静默,最终重试成功遵循成功通知的单独订阅,最终失败退出、超时、离线和拒绝执行分别计数,全部目标无法执行时也会汇总。中断或不完整的运行不会被当作成功。全部最终尝试结束后,Server 会先持久保存汇总,再尝试入队。入队失败或 Server 重启后会自动重试已记录的汇总,保留原运行标识和 30 分钟投递期限,并重新检查当前权限与订阅。中间重试结果不能作为完成证明。

汇总仅包含数量及任务、运行标识,不包含任务名称、命令或输出。点击通知打开经过认证且按本次运行筛选的结果。已展示的通知即使超过投递期限,点击仍保留经过认证的目标并检查 Server 当前访问权限;过期的新投递仍显示通用回退。任务已删除、运行不可用或权限丢失时显示可关闭的回退页面,旧账户和旧部署的通知无法导航。队列发送前再次检查当前管理员权限、所有者和订阅。无需通知组,成功任务通知需单独启用。

成功的任务运行

成功的任务运行默认关闭,仅在 Server 确认当前任务访问权限后显示。启用并保存订阅后,仅所有目标最终成功的完整运行会生成一个加密汇总,包括重试后成功的运行。此选项独立于任务最终失败,混合或失败的运行仅遵循失败订阅,不会重复发送成功汇总。中断、取消或不完整的运行无法生成成功汇总。

成功汇总沿用失败汇总的发起者或创建者归属、每个安装的资格检查、运行标识、认证导航和 30 分钟投递期限。内容仅包含数量和标识,不包含任务名称、命令或输出。保存失败会保留原来确认的偏好,未确认的选择和错误仍然可见。退出成功订阅或失去管理员权限后,队列在发送前重新检查访问权限并停止待发送的成功通知,已发出或被 APNs 接受的请求无法撤回。

安全规则通知

管理员可以启用 安全规则匹配,并保存 Server 确认的订阅。成员不能订阅。原始检测本身不会触发移动通知,必须通过已启用的 SSH 新 IP 登录、暴力破解或端口扫描规则。阈值、用户名/CIDR 排除、Server 范围、维护窗口和现有的滑动去重窗口继续生效。即使多条规则匹配,同一事件也只为每个符合条件的安装生成一个逻辑安全通知,无需通知组。外部渠道继续使用各自配置的通知组。

获得授权的 Agent WebSocket 会将原始检测交给 Server 的恢复队列,存储重试不再占用消息处理或生命周期锁。首次成功写入 raw 事件前仅在内存中保留,进程终止无法恢复尚未写入的事件。连接替换或关闭不会丢弃已接收的工作,但身份权限转移、撤销或能力移除会取消不再获得授权的 raw 写入和待准入工作。Server 保存原始安全事件、身份权限绑定、原始事件时间对应的维护决定和恢复标记,再将规则冷却与持久化的接收方意图一并提交。维护查询失败时仍保留原始历史和浏览器更新,规则准入继续等待,查询失败不会被视为允许通知。已保存的维护决定在延迟恢复、重启和维护窗口开始或结束后保持不变。共享规则去重键的事件按原始时间顺序准入,内存保留、缺失维护快照和数据库重新打开都不会让较新事件越过待处理的旧事件。等待中的事件只阻挡自己的键,其他就绪键和安装可以继续处理;持久化的规则冷却时间不会回退。最后在同一事务中为所有符合条件的安装加密入队。队列写入失败会保留原始历史、浏览器更新、防火墙动作和外部通知,不会产生部分设备入队;故障解除或 Server 重启后会自动重试原始意图。意图固定接收方所有者、会话和注册版本,入队前再次核验,替换注册不能继承旧意图。安全通知在事件记录后 30 分钟过期。每次尝试前,Server 都重新检查当前管理员角色、安全订阅和移动会话。降权或修改订阅会停止后续排队投递。多个设备分别判断资格。模糊网络失败后的重试仍可能造成设备重复显示。

Notification Service Extension 会本地化匹配的事件类型。点击后,应用验证部署/账号、当前管理员角色及资源身份,再打开对应的 Server 安全事件列表和事件详情。已删除、不可用或无权限的目标显示可返回的提示;旧账号或部署的通知不能导航。本地测试不能证明 APNs 在前台、后台或应用终止状态下的投递。

前台 APNs 投递仅显示一个系统横幅,WebSocket 只更新应用状态。

隐私边界

Server 负责账户、会话授权和接收者选择。Relay 可见 APNs 令牌、来源 IP、时间、请求大小、环境、事件/投递元数据及加密内容,不应收到内容密钥或明文通知。申请权限前会向用户显示此说明。

注册由已认证 Server 确认,并检查账号、安装、会话和注册版本。应用不调用 Relay。每次配对登录拥有独立作用域的共享内容密钥;替换账号和退出会移除旧密钥。待处理注册重试不能覆盖新账号。

Worker 公开且无状态。已知有效设备令牌可被用于垃圾通知或重放,解密失败时仍可能显示通用文字。不知道他人令牌也能用任意请求或自己的令牌消耗配额。加密保护业务内容,不提供准入授权。请求/资源硬上限和 isolate 内尽力限流只能减轻风险,不保证全局费用或完全阻止滥用。

Server 与 Relay 配置

通过 [push_relay].url 或 SERVERBEE_PUSH_RELAY__URL 指定独立 HTTPS Relay。无需通知组或旧 APNs 渠道。验证迁移会移除本账户的旧令牌,并持久隔离此安装与账户,关闭或注销现代通知后也不会恢复旧直连 APNs 群发。其他安装保留旧渠道。现有外部渠道继续使用自己的配置。

Cloudflare Worker 使用 WebCrypto JWT 签名与平台 fetch,topic 和 APNs 主机/环境允许列表固定。Worker 绑定包括 APNS_TEAM_ID、APNS_KEY_ID、APNS_TOPIC、APNS_ENVIRONMENTS,以及存储 PKCS#8 PEM 文本的 APNS_PRIVATE_KEY secret,仅属于 Relay。不再需要 App Attest、challenge/grant 服务、Relay 数据库、Bun/OpenSSL 生产运行时或自建 HTTP/2 池。测试不得指向 Heeler 的 Relay。

隔离签名与部署手册、分层排障及真实设备验收记录参见 Push Relay 运维。本地检查成功不建立真实设备验收证据。

安全考量

  • 令牌轮换:每次使用时轮换刷新令牌(一次性使用),已消费的刷新令牌不能认证 API 或再次刷新。保留的哈希只能撤销原会话,使分阶段升级或轮换响应丢失后的清理仍可完成
  • 固定过期:访问令牌固定 15 分钟过期(无滑动续期),以限制被盗后的暴露时间
  • 安全存储:令牌使用适当的可访问性级别存储在 iOS Keychain 中
  • 会话过期:过期的访问令牌会话每小时清理一次。该任务不会删除配对设备的刷新会话:设备列表会在刷新会话过期后将其隐藏;刷新令牌轮换会保留原会话身份和安装注册;登出或撤销会删除会话及其保留的撤销证明哈希。

故障排除

二维码无法扫描

  • 确保二维码在屏幕上清晰显示
  • 检查二维码是否已过期(5 分钟超时)
  • 尝试从 Web 应用生成新的二维码

通知设置失败

  • 检查 Relay 地址及其 HTTPS 信任链。
  • 在设置 → 通知中查看权限、验证与保存错误。
  • 确认配对设备未被撤销,会话未过期。
  • sandbox/production APNs 环境须与签名应用匹配,并检查嵌入的 Notification Service Extension。模拟器通过不代表真实 APNs 投递。
  • 注册内容密钥前应配置最终的 HTTPS Server 地址。Server 请求拒绝重定向,设置失败后可在配置的地址重试。
  • 核对应用私有凭据组及应用与扩展共享内容密钥组的签名。解密失败时仅显示通用文字。
  • 可启用告警触发与恢复,管理员还可启用任务最终失败及单独的成功的任务运行。当前管理员可启用安全规则匹配,并使用当前安装的测试操作检查设置。

认证失败

  • 如果应用显示"会话已过期",将自动刷新令牌
  • 如果刷新失败,需要使用新的二维码重新配对
  • 检查服务器时间是否正确同步(NTP)

技术细节

认证流程

  1. 登录/二维码配对:POST /api/mobile/auth/login 或二维码配对端点 → 返回 access_token + refresh_token
  2. API 请求:在请求头中包含 Authorization: Bearer {access_token}
  3. 令牌刷新:收到 401 时,POST /api/mobile/auth/refresh 携带 refresh_token → 新的令牌对
  4. 登出:POST /api/mobile/auth/revoke,携带仅可撤销会话的凭据和原会话的 expected_session_id;旧的已认证 /logout 路由仍用于兼容

离线退出恢复

修改已验证通知设置前,应用会为当前移动会话确认仅可撤销该会话的凭据。已建立的会话离线退出时,应用先将撤销凭据保存到主应用私有钥匙串,再清除普通登录凭据。启动、回到前台、网络恢复及登录或配对前都会重试待处理清理,且绝不会使用替换账号的凭据。确认原会话已不存在,不会删除使用同一安装标识的其他登录。

升级后的安装若尚无已确认的撤销凭据,需要先连接服务器才能完成安全退出。存储错误或待处理清理列表已满也会阻止破坏性凭据清除或替换登录;应用会明确报告,而不会丢失原会话的清理凭据。迁移和凭据引导期间,已有内容密钥及测试标识保持原有作用域。服务器端退出无法撤回已发送或被 APNs 接受的通知。

升级后的会话若缺少已确认撤销凭据,且普通凭据被永久拒绝,应用会显示恢复会话并暂停普通已认证请求;重启或保留钥匙串数据的重装后仍会进入恢复界面。使用原账号密码及所需的验证码完成验证。服务器仅清理准确的原会话或确认其已不存在,之后应用才释放已保存身份并返回登录页。重试安全退出仅重试原清理凭据,不创建新登录。响应丢失、服务器不可用、服务器版本不支持或身份无法定位时,恢复记录仍会保留;若原凭据无法定位会话,验证账号后仅列出原账号、原安装的会话,包括过期会话。请根据设备名称和时间选择原会话,再确认退出。提交清理前会先保存所选 ID,因此响应丢失后重启仍可重试准确目标。应用不会自动选择其他会话;无法归属的遗留状态会明确报错并继续保留。

WebSocket 连接

iOS 应用维护 WebSocket 连接以获取实时更新:

  • 连接 URL:wss://your-server/api/ws/servers
  • 握手期间通过 Authorization: Bearer 头进行认证
  • 自动重连,使用指数退避策略
  • 访问令牌过期时连接自动关闭(重连触发刷新)