2.3.0:手表界面精简 + 播放器 + 鼠标重做

手表端
- 功能页从 10 个杂项精简到 7 个(屏幕/鼠标/媒体/文件/电脑/语音/电源)
- 删掉:游戏封锁、待办、掷骰子、抽奖、壁纸、显示器开关、定时关机、
  剪贴板历史、性能/磁盘/电量、文件夹浏览、教室限制等
- 改成显式列按钮,不再把电脑端所有功能组无脑铺到表盘
- 远程鼠标控制重做:滑动区 + 左键/滚轮/右键三按钮
  滚轮点按=中键、上下滑=滚动
- 新增视频/音乐播放器(手表本地播放):进度拖动、左右滑快进退10秒、
  点画面播放暂停、上一/下一、播完自动下一首

电脑端
- 新增 kill_all(结束所有进程),白名单保护系统关键进程和自身
- 新增 media_list / media_pull(播放器数据源)
  安全边界:只允许媒体目录,用 relative_to 判断,防同前缀兄弟目录绕过

中转站
- known_devices 从 ID 集合改成「设备ID -> 配对码」映射
- 修复:管理员改码后关机超过 6 小时,改码会被超时清理冲掉
- 老格式 state 文件平滑升级
This commit is contained in:
xmz7891
2026-10-18 11:39:14 +08:00
parent 1d368979aa
commit 2061f9525f
50 changed files with 13812 additions and 584 deletions
+115
View File
@@ -0,0 +1,115 @@
# -*- coding: utf-8 -*-
r'''给 xxmxxs.top 签 Let's Encrypt 证书,并加回 443 块。
== 现在的状态 ==
* `xxmxxs.top` 的 A 记录已经指过来(走 Cloudflare 代理)✓
* `www.xxmxxs.top` **还没解析** —— 先不带它签
* 80 端口上博客已经能用(`http://<服务器IP>/console` 可以进控制台)
== 为什么先不签 www ==
`certbot -d xxmxxs.top -d www.xxmxxs.top` 会**同时校验两个域名**。
www 没解析的话整张证书都签不下来(Let's Encrypt 要求所有域名都通过校验)。
所以先签主域名,等 www 记录加了再 `--expand` 补进去。
== 走 Cloudflare 代理时的一个风险 ==
ACME 的 HTTP-01 挑战要求:
http://xxmxxs.top/.well-known/acme-challenge/<token>
能直接返回文件。
但 Cloudflare 如果开了 **"Always Use HTTPS"**,会把 80 端口的请求
301 到 https —— **certbot 就跟不上那个跳转,签不下来**。
不过 Cloudflare **默认不代理 `.well-known/acme-challenge/`**,
而且我们是 `--nginx` 插件(它会临时插一个 location)。
真出问题的话,报错信息会明确说"challenge 拿不到",
那时候再去 Cloudflare 加一条"绕过规则"。
== 443 块怎么加回来 ==
之前在配置文件里**故意没写** 443 段(没证书时 `nginx -t` 会失败:
"no ssl_certificate is defined")。
现在证书有了,用 `certbot --nginx` 让它**自己写** —— 比我手写靠谱,
因为它会把续期需要的所有行都带上。
'''
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "_build"))
from lssh import run # noqa: E402
def main() -> int:
print("=" * 62)
print(" 给 xxmxxs.top 签证书 + 开 HTTPS")
print("=" * 62)
print()
print("── 1. 签证书(certbot 自己改 nginx 配置)──")
out = run(r'''
sudo certbot --nginx -d xxmxxs.top \
--non-interactive --agree-tos --register-unsafely-without-email \
--redirect --keep-until-expiring 2>&1 | tail -20
''', timeout=900, quiet=True)
print(out[1] if isinstance(out, tuple) else out)
print()
print("── 2. 复核 ──")
out = run(r'''
echo " --- 证书文件 ---"
sudo ls -1 /etc/letsencrypt/live/ 2>/dev/null | sed 's/^/ /'
echo
echo " --- 证书信息 ---"
sudo openssl x509 -in /etc/letsencrypt/live/xxmxxs.top/fullchain.pem \
-noout -subject -dates 2>/dev/null | sed 's/^/ /'
echo
echo " --- nginx 配置现在有几个 server 块 ---"
sudo grep -cE "^\s*server \{" /etc/nginx/sites-available/halo | sed 's/^/ halo: /'
echo
echo " --- 443 块有了吗 ---"
sudo grep -c "listen 443 ssl" /etc/nginx/sites-available/halo | sed 's/^/ listen 443: /'
echo
echo " --- nginx 检查 + 重载 ---"
sudo nginx -t 2>&1 | tail -2 | sed 's/^/ /'
sudo systemctl reload nginx && echo " 重载完成" || echo " 重载失败"
echo " nginx: $(systemctl is-active nginx)"
echo
echo " --- 各入口复核 ---"
printf " %-42s " "http://<服务器IP>/console (IP 控制台)"
curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 10 http://127.0.0.1/console
printf " %-42s " "https://xxmxxs.top/ (博客)"
curl -s -o /dev/null -w "HTTP %{http_code} %{size_download} 字节\n" --max-time 15 https://xxmxxs.top/
printf " %-42s " "https://xxmxxs.top/console (控制台)"
curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 15 https://xxmxxs.top/console
printf " %-42s " "http://xxmxxs.top/ (应该 301 到 https)"
curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 15 http://xxmxxs.top/
printf " %-42s " "https://yk.xxmxxs.top/ (中转站没坏)"
curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 15 https://yk.xxmxxs.top/
printf " %-42s " "http://<服务器IP>:3001/ (直连 Halo)"
curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 10 http://127.0.0.1:3001/
printf " %-42s " "http://<服务器IP>:9100/ (官网)"
curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 10 http://127.0.0.1:9100/
echo
echo " --- ACME 挑战路径还是通的吗(关系到 90 天后能不能续)---"
printf " %-42s " "http://127.0.0.1/.well-known/acme-challenge/probe"
sudo sh -c 'echo ok > /var/www/html/.well-known/acme-challenge/probe'
curl -s -o /dev/null -w "HTTP %{http_code}\n" --max-time 8 -H "Host: xxmxxs.top" http://127.0.0.1/.well-known/acme-challenge/probe
sudo rm -f /var/www/html/.well-known/acme-challenge/probe
''', timeout=400, quiet=True)
print(out[1] if isinstance(out, tuple) else out)
return 0
if __name__ == "__main__":
sys.exit(main())