|
|
c597fa1991
|
fix(auth): 登录页恢复自动深浅色(我在重写模板时造成的回归)
原 portal-auth 的登录页有 prefers-color-scheme 检测 + 手动切换 +
localStorage 记忆;我把它换成内置登录服务时只写了亮色,自动深浅色因此消失。
- 默认跟随系统(prefers-color-scheme),手动切换后写入 localStorage
- 深浅两套 CSS 变量(背景/卡片/边框/文字/输入框/错误提示/阴影)
- 右上角切换按钮,补 aria-label
- 加 color-scheme + prefers-reduced-motion
- 测试:断言主题检测、切换按钮、no-store;并断言 redirect 被转义(注入防护)
|
2026-09-11 23:14:45 +08:00 |
|
|
|
b941d8e8e3
|
fix(gateway): 错误页必须跳过 auth_request,否则上游故障会变成 401
实测:上游连接被拒(502)时 nginx 内部跳转 /500.html,而服务端的
auth_request 被这个内部请求继承 → 用户收到 nginx 默认 401 页,
自定义 404/500 永远显示不出来。
错误页及其静态资源一律 auth_request off,并加单测锁住。
|
2026-09-11 22:33:45 +08:00 |
|
|
|
1844586feb
|
fix(gateway): TLS 段的 http2 必须写成 listen 参数
容器的 nginx 是 1.22,独立的 `http2 on;` 会报 unknown directive
(该指令 1.25.1 才引入;原 portal-nginx 用 nginx:latest 所以没暴露)。
改为 `listen PORT ssl http2;`,1.22 与 1.25+ 都可用,并加单测锁住。
本轮由旁路端口 TLS 验证发现;apply 的校验-保留机制正确拦下了这次坏配置。
|
2026-09-11 22:09:57 +08:00 |
|
|
|
53beff646a
|
feat(admin): 现有配置导入 + 添加表单补齐认证/导航开关 + 统一登录账号设置 + 设置分组
针对反馈的五个问题:
1. 后台"没有映射":新增 /admin/api/gateway/import 与界面「从现有 nginx 配置导入」,
把老统一入口的 nginx 配置贴进来即可解析出全部「域名 → 后端」初稿
(含 requireLogin / 免认证路径 / SSE 流式 / 备案注入 / 自签证书 / auth 与 portal 类型)。
解析只读不落盘,确认后才保存;导入默认不接管导航,避免一导入就改掉手工导航。
2. 添加转发时没有导航选项:添加表单补齐「同时加入 Dashy 导航 / 分组 / 名称 / 描述 /
图标 / 自动抓取」。
3. 添加转发时没有 portal 保护选项:添加表单补齐「启用 portal 统一登录保护」,
并补上 WebSocket 透传与上传上限。
4. 设置里无法配置 portal 账号:新增统一登录账号卡片,账号存数据卷
(portal-auth.json,只存加盐哈希),优先级 数据卷 > 环境变量,
改完立即生效、无需重新部署;会话校验按当前用户名,改账号后旧会话失效。
5. 设置项太乱:按用途分组(站点与外观 / 导航内容 / 历史记录 / 转发与统一登录 / 高级),
外观卡片并入站点组。
另修两个本轮引入的缺陷:
- 容器假 unhealthy:内部端口改 18080 后,基础镜像的 HEALTHCHECK 仍指向 8080;
部署脚本生成的 Dockerfile 现在显式覆盖为 :18080/healthz。
- kind=auth 不依赖 portal-auth 容器,指向内置登录服务;避免生成空 proxy_pass。
测试:nginx 配置解析(含兜底段忽略、多域名段、类型判定、默认不接管导航)、
垃圾输入报错、账号存储(不明文、可校验、改名后旧口令失效)、auth 类型生成。
|
2026-09-11 22:00:09 +08:00 |
|
|
|
994d93cc98
|
feat(gateway): 一体化统一入口——路由与 Dashy 导航同一份数据、内置登录、原自定义错误页
目标:一个 HomeDash 容器取代 navi + portal-nginx + portal-auth。
- Route 扩展为"反代 + 导航"一条记录:kind(proxy/portal/auth)、streaming、
insecureTls、bypassPaths、injectBeian,以及 navEnabled/navSection/navName/
navDescription/navUrl/navIcon/navAutoIcon
- 保存路由时**同时**写 gateway.yml 与 conf.yml 的导航项(gateway_nav.go):
同 host 接管而不是重复、未勾选导航的会被清理、无关手工项与系统「历史访问」分组
一律不动;两步任一步失败都回滚(避免后台显示与导航页各说各话)
- 未知域名与上游故障改用**内置自定义 404/500 页面**(portal/ 目录),
不再是一行纯文本;HTTP→HTTPS 跳转段用 RedirectPort 复刻原 3081 设计
- 内置统一登录(auth.go):HMAC 签名 cookie、恒定时间比较、登录跳转白名单校验,
portal-auth 容器可以退场
- 自动抓图标对托管导航项同样生效(history-server 识别 naviGatewayAutoIcon)
- 后台卡片补齐"加入导航/分组/名称/描述/图标/自动抓图标/服务类型"字段
- 内部入口端口 8080 → 18080:为一体化 host 模式让开宿主机 blog(:8080)
- 修掉上一轮编辑写坏的 deploy/zd.sh 一行(会让脚本直接失败)
测试:新增自定义错误页、portal 类型、导航字段校验、导航同步(接管/清理/保留)、
分组不存在必须报错等用例;admin-server 与 history-server 全绿。
|
2026-09-11 21:27:40 +08:00 |
|
|
|
5f6fca5c59
|
fix(gateway): 未知域名必须被兜底拒绝,不能落进某条路由的后端
实测发现:入口端口上若没有匹配 server_name 的请求,nginx 会交给该端口排序
第一的 server 块,于是一个打错的域名会访问到别的服务(若第一条恰好是开放
路由,等于把该服务暴露在错误域名下)。现在为 HTTP/HTTPS 各生成一个
default_server 返回 404,并在单测中断言其存在。
|
2026-09-11 20:34:20 +08:00 |
|
|
|
19d082e70a
|
feat(gateway): 统一入口路由表(后端基础层)——"哪些服务走统一认证"变成一条数据
目标:不再手工维护外部 nginx 配置,把"域名→内网后端、是否走统一登录认证"
变成后台可编辑的数据,由本进程生成 nginx 配置并热加载。
本提交只做基础层(纯 Go、可测、零行为变更):
- gateway.go:Route/H gatewayConfig 数据模型 + ValidateRoute + RenderGatewayConf
· 认证**按路由**决定:RequireLogin 为真才生成 auth_request 与登录跳转,
也就是"哪些服务受统一认证保护"完全由路由表决定
· 支持 websocket 透传、单域名上传上限、HTTPS 段(可同时生成旁路端口)
· 路由表单独存 gateway.yml(不混进 Dashy 的 conf.yml),写坏了也不影响导航页
- API:GET/POST /admin/api/gateway/routes(保存)、POST /admin/api/gateway/apply
· apply 的顺序是 生成 → nginx -t 校验 → 通过才 reload;**校验失败把上一份可用
配置写回去并把 nginx 原始报错回给界面**,避免"点了应用整个入口挂掉"
- nginx.conf 加 include /app/data/gateway/*.conf(生成物在容器自己的卷里,
不碰宿主机文件,天然避开"单文件 bind mount 不能用 sed -i"的坑)
- 生成物默认监听旁路端口(8081/8443):可以先与正式入口并存验证,再切 80/443
测试:受保护域名必须有 auth_request、未受保护域名必须没有;websocket/上传上限;
空域名/带协议域名/非 http 后端/域名重复/需认证却无认证地址/启用 HTTPS 却无证书
六种非法输入必须报错;缺文件时回落默认配置、保存后回读一致。
|
2026-09-11 20:17:57 +08:00 |
|
|
|
0d9619e446
|
feat(admin): 导航分组可增 / 可改名 / 可删;初始状态无分组
后台此前只能往已有分组里加服务,分组本身是写死在 conf.yml 里的,
用户无法增删。现在新增「导航分组」卡片:
- POST /admin/api/section 新增(重名 409、空名 400)
- POST /admin/api/section/update 改名/换图标
- DELETE /admin/api/section 删除;非空分组必须 force=1(二次确认),
避免误点一下连带删掉一组服务
「历史访问」分组由 history-server 依据浏览记录重建,改名/删除/手工新建
都会被它覆写回来,所以一律 409 并说明原因 —— 否则用户以为删掉了,
下次同步又"长"回来。
初始状态无分组:conf.example.yml 的 sections 改为空数组,后台在两个位置
给空态提示(「还没有任何分组」/「先创建分组」,并把"添加服务"置灰)。
补上原本缺失的一环:rebuildDashySections() 原先只更新已存在的
「历史访问」分组、从不创建它,新装用户永远看不到历史分组;现在缺了就补建
(完全空配置时不补,保持"初始无分组")。
测试覆盖:新增/重名/改历史分组/删历史分组/删非空(无 force 拒绝)/force 删除,
以及删除后的分组名列表断言。
|
2026-09-11 19:52:19 +08:00 |
|
|
|
22c405d2a0
|
feat(admin): 新增可内嵌性三态探测 /admin/api/frameable
Dashy 的「工作空间」用 iframe 打开应用,被 X-Frame-Options /
CSP frame-ancestors 拒绝时浏览器只给一片空白,而且 JS 无法区分
「被拒绝」与「加载中」(onload 一样触发)。所以由服务端读响应头。
实测 24 个应用:19 个可内嵌;Gitea(含内网 IP) 与 docker.com 是
SAMEORIGIN,Dify 是 DENY。
三态而非布尔,因为探测本身会失真:
- conclusive=true frameable=false → 有明确拒绝证据(XFO / frame-ancestors)
- conclusive=true frameable=true → 2xx 且无拒绝头
- conclusive=false → 探测被 WAF 拦成 403、或跳到了别的主机
这类不给结论,前端照常尝试内嵌,但在工具条里说明原因并留出新标签页退路。
两个关键细节:
1) 转发浏览器自己的 Cookie。门户后面的应用对未登录请求会 302 到登录页
(登录页没有 X-Frame-Options),不转发会话就会把「重定向到登录页」
误判成「可内嵌」——这是线上真实发生过的误判。
2) 用普通浏览器 UA。自造的 "HomeDash embed check" UA 会被 WAF 当机器人拦成 403。
测试覆盖:无头/有 XFO/有 CSP frame-ancestors/WAF 403/带与不带 Cookie。
|
2026-09-11 19:04:38 +08:00 |
|
|
|
c04d00d4de
|
feat(admin): 历史记录可在后台逐条删除/清空
此前后台**没有任何历史管理入口**,只有一条需要 admin token 的
DELETE /api/history/(清空全部),所以用户根本无法删除记录。
- history-server: 新增 DELETE /item?url=<url> 删除单条并重建分组;
CORS 允许 Authorization 头
- admin-server: 新增 /admin/api/history(GET 列表 / DELETE 清空)与
/admin/api/history/item(DELETE 单条),服务端带 token 转发给
history-server —— 令牌只在容器内部使用,浏览器侧无需保存
- admin UI: 「历史访问」卡片,列出记录 + 逐条 ✕ + 清空全部(均二次确认)
标题为空或本身是 URL 时显示简洁域名
|
2026-09-11 17:03:33 +08:00 |
|
|
|
e4967b99ee
|
feat(admin): 备案号可编辑,页脚模板由服务端生成
备案号原来只能写死在 pageInfo.footer 的 HTML 里。现在 /admin/ 站点信息
拆出「ICP 备案号」「公安备案号」两个输入框,页脚 HTML 由服务端
beianFooter() 统一按模板生成(含 html.EscapeString 转义),
自定义页脚 HTML 降级为「高级」折叠项;旧 footer 会被解析回填到字段。
conf.example.yml 里重复的 .navi-search-bar 规则已由 web/navi.css 接管,删除。
|
2026-09-11 16:25:26 +08:00 |
|
|
|
de795de0fb
|
feat(install): show the sync token on the install page
插件必须填 NAVI_SYNC_TOKEN,但页面上没有任何地方能看到它 —— 用户只能去翻
.env,实际就是配不起来。
- admin-server 新增 GET /admin/api/sync-info,返回 syncToken / hasToken。
放在 /admin/ 下而不是 /api/ 下是必须的:插件上报用的 /api/history/sync
被门户 auth_request 放行,若令牌挂在同一前缀下就等于公开。
实测 /api/history/sync-info 返回 401,只有 /admin/api/sync-info 能取到。
- 安装引导页把「第一步」改为填写两项(服务地址 + 同步令牌),各自可复制;
服务端未设令牌时提示留空即可;未登录时提示需先登录门户。
- README 补充对应说明。
|
2026-09-11 11:49:31 +08:00 |
|
|
|
e409f967a9
|
feat(admin): custom wallpaper for the nav background
- admin-server 新增 GET/POST /api/wallpaper:
multipart 上传(png/jpg/webp/gif/svg,上限 8MB)或 JSON 直接给 URL,
服务端把一段带标记的 CSS 写入 appConfig.customCss(标记块可反复替换,
不碰主题其余部分),并记录 appConfig.wallpaper / wallpaperDim。
- 上传的图片落在 data 卷 wallpapers/,nginx 以 /wallpapers/ 提供
(长缓存,文件名带时间戳)。
- 遮罩:壁纸上面铺一层可调强度的白色 linear-gradient,默认 0.45,
否则玻璃卡片上的文字在照片上会读不清。
- 安全:URL 校验只允许 / 或 http(s):// 开头且不含引号/括号/换行,
避免注入到 CSS;类型判定走正文特征而非文件名。
- admin UI 增加「外观」区块:上传/填 URL/遮罩滑块/应用/移除 + 预览。
实测:上传 → /wallpapers/wall-*.png,web 200 image/png,
body background-image 为遮罩+图片,移除后恢复默认渐变。
|
2026-09-11 11:46:53 +08:00 |
|
|
|
f8c4771828
|
fix(admin,theme): make admin actually work; glass theme targets real DOM
后台之前有两处让它完全不可用的问题(都属于「看着有、实际不工作」):
1. 写操作 401 —— admin UI 从未带 Authorization 头,而 admin-server 强制校验
NAVI_ADMIN_TOKEN。于是添加/删除一直静默失败。
2. JSON 键名不匹配 —— Section/NavItem 只有 yaml tag,没有 json tag,
接口返回 {"Name":..,"Items":[{"Title":..}]},而前端读 s.name / it.title,
渲染直接抛异常(菜单区永远停在「加载中…」)。
修法:
- admin-server:token 改为**默认不校验**(/admin/ 已在外层门户登录墙内,
用户确认无需叠加),仅当显式设 NAVI_ADMIN_REQUIRE_TOKEN=1 时才校验;
历史 DELETE 不受影响(那条路径被门户放行,仍必须自带 token)。
- 补 json tag;Config/Section/NavItem 加 yaml ",inline" 保留未知键,
避免保存 conf.yml 时把不认识的配置(layout/pages/item 的 target 等)丢掉。
- 新增 /api/pageinfo(标题/副标题/页脚/顶部导航可在后台编辑)与
/api/icon(图标上传,限 png/svg/jpg,512KB)。
- 重写 admin UI:站点信息 + 顶部导航编辑、图标上传(.ico 用 canvas 转 PNG,
因为 Dashy 的 isImage() 只认 svg/png/jpg)、可选令牌。
主题:旧 customCss 大部分是死代码 —— .tile / .item-group / .item-group-outer
在页面里根本不存在(querySelectorAll 计数为 0),卡片灰底其实来自 a.item,
而 .home 的不透明背景盖住了 body 渐变,所以玻璃效果一直看不出来。
现按真实类名(a.item / .item-wrapper / .collapsable / .collapsible-content /
.home / header)重写,并加入工作空间侧边栏的溢出修复。
安装页:.btn 自带 display 会盖掉浏览器默认的 [hidden]{display:none},
未配置商店时「一键安装」按钮仍然可见且 href 为空(点了没反应)。
现显式兜住 [hidden],并把浏览器识别补全(iOS/Android 单独提示为不可安装、
Edge/Brave/Vivaldi/Opera 给出各自的 extensions 地址、优先用 userAgentData)。
|
2026-09-11 11:43:44 +08:00 |
|
|
|
f0b318be45
|
feat: complete browser extensions + token auth for history/admin APIs
- Extensions: rewrite both Chrome MV3 & Firefox MV2 with reliable
chrome.history.search incremental pull (not onVisited), local search-engine
filtering, URL dedup, 30s alarm, retry queue, Bearer token header
- Add icons (16/48/96/128) for both browsers
- Manifest fixes: chrome action popup, firefox options_ui + browser shim
- history-server: require NAVI_SYNC_TOKEN for POST /sync & GET history,
NAVI_ADMIN_TOKEN for DELETE; fix RWMutex deadlock (unlock before
sortDashyFavorites) that stalled syncs with valid token
- admin-server: require NAVI_ADMIN_TOKEN for item add/delete writes
|
2026-09-08 22:35:54 +08:00 |
|
|
|
7e49d2b51c
|
feat: HomeDash - unified self-hosted navigation portal
Single-container navigation service combining:
- Dashy dashboard + SearXNG metasearch + history sync API + admin WebUI
- Go services for history/admin APIs, nginx as unified entry
- Browser extensions (Chrome MV3 / Firefox MV2) with 30s batched sync
- Production guide: portal-nginx unified auth reverse proxy + webui4frpc/frp tunnel
- Fully sanitized (no internal IPs/domains/credentials)
|
2026-09-08 22:25:00 +08:00 |
|