LHL's Blog - LHL
type: channel
link: https://blog.lhl.one/author/1/
description: LHL
items: LHL's 公益主机说明
items: Typecho 个人主页插件 - TypechoBio
items: Surface 更新到 Fedora 44 开机无法进入桌面环境
items: Typecho 最好用的编辑器 - AB Vditor
items: Typecho 头像源与自定义管理插件 - AB Avatar
items: Typecho OAuth 第三方登录插件 - AB OAuth
items: 兰空图床对接超星学习通网盘 (支持多用户绑定)
items: 内网穿透使用说明 (LHL's Shop专用)
items: Typecho Joe再续前缘v2 主题开心思路
items: Typecho Mirai 主题开心思路

LHL's 公益主机说明
type: item
date: 2026-05-27T19:12:00+08:00
description: 本文章主要针对 LHL's Shop 中的 DC2 Free系列如何解析？通过 CNAME解析到面板中给出的 域名即可，此时只能 IPv6访问，建议开启CDN如Cloudflare的小黄云和腾讯Edge One为什么免费机要收取1元费用？由于免费的属性，可能有用户将大量低频访问内容放到服务器中，且长时间不使用，为了避免免费资源的浪费，因此设置每年1元的费用。页脚标注公益机器需要在页脚标注，若建站30天内未加脚标且流量较大，可能会进行流量限制。本站由 LHL's Host 提供公益主机支持

Typecho 个人主页插件 - TypechoBio
type: item
date: 2026-05-26T17:00:00+08:00
description: TypechoBio 个人主页插件支持指定域名，复用Typecho的评论系统，并指定评论文章ID。安装方式方式一：AB-Store 一键安装（推荐）安装 AdminBeautify 插件后，进入后台 AB-Store 应用商店，搜索 TypechoBio 即可一键安装并获取后续更新。方式二：手动安装下载最新 Release 压缩包解压为 TypechoBio 文件夹上传至 Typecho 的 usr/plugins/ 目录登录后台 → 控制台 → 插件管理 → 启用 TypechoBio方式三：Git 克隆cd /path/to/typecho/usr/plugins/ git clone https://github.com/lhl77/TypechoBio.git TypechoBio可安装主题ImsyyDuckfolioZyyoDmegoWexuoIAMITypechoBio 主题适配文档本文面向 TypechoBio 主题开发者，目标是把“一个现成前端页面或主题源码”稳定适配到 TypechoBio。文档内容基于当前插件实现整理，和实际代码行为对齐，适用于以下场景：新增一个本地主题到 usr/plugins/TypechoBio/templates/<theme>/将外部 HTML、静态站点、Vite 构建产物、主题源码迁移到 TypechoBio为主题接入插件统一的配置系统、评论区、独立域名运行时上下文为主题打包成远程主题市场可安装的 zip 包1. 运行模型TypechoBio 不是 Typecho 前台主题，而是“独立域名命中后接管输出”的插件入口。当前请求命中插件后，执行链路大致如下：插件根据 bio_hosts 判断当前 Host 是否需要被 TypechoBio 接管。若命中，则先处理主题专属 API，再处理主题静态资源请求。非资源请求会进入 usr/plugins/TypechoBio/templates/index.php。templates/index.php 读取当前启用主题、主题配置、用户状态、评论数据等上下文。最终 require usr/plugins/TypechoBio/templates/<theme>/home.php 输出完整页面。这意味着：home.php 需要自己输出完整 HTML 页面，不要假设 Typecho 默认前台模板会包裹你。主题运行时可直接访问数据库、登录态、插件配置，但应优先使用插件已整理好的 $typechoBioContext。资源、评论、配置都应按 TypechoBio 的约定来接，而不是直接照搬原主题的 CMS 假设。2. 主题最小目录结构一个主题至少要满足下面的目录结构，才能被 TypechoBio 识别：usr/plugins/TypechoBio/ └── templates/ └── my-theme/ ├── home.php ├── theme.json ├── assets/ │ ├── app.css │ └── app.js ├── images/ └── ...识别规则很严格：templates/ /home.php 必须存在templates/ /theme.json 必须存在两者缺一不可，否则 discoverThemes() 不会把这个目录识别为可用主题建议：主题目录名只使用字母、数字、下划线、连字符目录名与 theme.json 中的主题标识保持一致把当前主题的静态资源全部放在本主题目录下，不要散落到插件根目录3. home.php 的职责home.php 是主题真正的入口文件，建议把它当成“页面壳层模板”。它至少应负责：输出完整 HTML 文档结构读取 $typechoBioContext根据 themeConfig 渲染页面内容正确引用当前主题静态资源按需接入评论区、代理接口、额外共享片段一个最小可运行的例子如下：<?php if (!defined('__TYPECHO_ROOT_DIR__')) { exit; } $ctx = isset($typechoBioContext) && is_array($typechoBioContext) ? $typechoBioContext : array(); $themeConfig = isset($ctx['themeConfig']) && is_array($ctx['themeConfig']) ? $ctx['themeConfig'] : array(); $siteTitle = isset($ctx['siteTitle']) ? (string) $ctx['siteTitle'] : 'TypechoBio'; $themeAssetBase = iss…

Surface 更新到 Fedora 44 开机无法进入桌面环境
type: item
date: 2026-05-20T19:35:00+08:00
description: 文章撰写时间 2026年5月20日，本来想说洗个澡然后有新系统用，结果一直黑屏，发现卡在黑屏闪烁光标更新前提示 libwacom更新后不支持，预计跟之前安装过的 surface-linux相关，于是翻找 issue查看有无解决方案。找到的对应issue: Fedora 44 error手动下载安装官方源的libwacomsudo dnf download libwacom libwacom-data sudo rpm -ivh --nodeps --force libwacom-*.rpm关键操作由于新安装的 libwacom-data并没有建立依赖关系，导致 gdm依旧会启动失败，有如下日志：journalctl -u gdm -b 0 | grep -iE "error|critical|fail" May 07 09:00:57 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:00:57 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:00 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:00 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:02 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:02 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:05 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:05 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:08 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:08 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:11 surfacego gdm[1305]: Gdm: GdmDisplay: Session never registered, failing May 07 09:01:11 surfacego gdm[1305]: Gdm: GdmLocalDisplayFactory: maximum number of display failures reached. Giving up.那么解决办法就是重新处理包之间的依赖关系，防止系统误删依赖于该库的桌面环境组件。sudo dnf swap libwacom-surface-data libwacom-data接着重启机器即可～或者直接重启 gdmsudo systemctl restart gdm # 重启也行 sudo reboot

Typecho 最好用的编辑器 - AB Vditor
type: item
date: 2026-05-16T00:30:00+08:00
description: 本编辑器 AB Vditor 基于插件AdminBeautify，Vditor基于原版3.11.2版本支持 所见即所得、实时预览、分屏编辑 这三个Vditor的模式，并可快速切换支持 短代码 显示，如图为 Mirages 主题自带的一些工具照顾到兼容性，故使用 单独的复制界面，从而避免某些情况下兼容性的问题支持 全屏编辑，让您更加专注于创作～Github 地址: AB Admin

Typecho 头像源与自定义管理插件 - AB Avatar
type: item
date: 2026-05-08T18:16:00+08:00
description: AB AvatarAdmin Beautify 专用头像管理插件，支持更换Gravatar源(本地代理)，支持自定义头像功能特色功能说明Gravatar 多源切换支持官方 / loli / Cravatar / 自定义域名 / 本地代理代理地址编码本地代理使用 token 编码参数，避免暴露明文 Gravatar 格式本地头像专属路由本地存储头像通过签名 token 路由访问，不直接暴露文件路径自定义头像上传个人设置页与用户编辑页支持上传、裁剪、压缩、恢复PicUp 集成可选 PicUp 存储后端，支持上传策略（Profile）选择管理面板插件设置页内置“自定义头像管理”，支持恢复为 Gravatar安全防护支持代理防盗链、每 IP 限流、代理缓存天数配置截图编辑头像可上传自定义头像上传自行裁剪安装方式一：AB-Store 一键安装（推荐）安装 AdminBeautify 插件后，进入后台 AB-Store 应用商店，搜索 AB Avatar 即可一键安装并获取后续更新。方式二：下载压缩包前往 GitHub 仓库 下载源码或发布包解压后将目录重命名为 AdminBeautifyAvatar上传到 Typecho 的 usr/plugins/ 目录在后台进入 控制台 -> 插件，启用 AdminBeautifyAvatar方式三：Git 克隆cd /your-site/usr/plugins/ git clone https://github.com/lhl77/Typecho-Plugin-AdminBeautifyAvatar.git AdminBeautifyAvatar目录示例：your-site/ └── usr/ └── plugins/ └── AdminBeautifyAvatar/依赖说明必需：AdminBeautify可选：PicUp（作为头像存储后端）当 AdminBeautify 未启用时，插件设置页仅显示依赖提示，不显示其它配置项。主要配置项前台 Gravatar 源：官方 / loli / Cravatar / 自定义 / 本地代理本地代理上游源、缓存天数、限流、防盗链允许用户上传自定义头像自定义头像大小限制（MB）头像存储后端：本地 / PicUpPicUp 上传策略（Profile）前台自动替换 Gravatar 地址路由说明路由作用/ab-avatar/gravatar/{token}头像代理路由（token 编码参数）/ab-avatar/local/{token}本地头像专属访问路由（签名 token）/ab-avatar/upload当前登录用户上传自定义头像/ab-avatar/restore当前登录用户恢复为 Gravatar/ab-avatar/manage管理员恢复指定用户头像 / 代上传使用建议先启用 AdminBeautify，再启用本插件默认推荐“前台 Gravatar 源 = 本地代理”若站点开启 CDN / 缓存，建议保持 proxy_hotlink_protection 与 proxy_rate_limit_per_min 为开启状态若使用 PicUp，请先确认 PicUp 插件已正确配置并可正常上传常见问题1) 访问代理头像返回 invalid token说明当前链接不是插件生成的编码代理地址，或 token 已损坏。请确保头像 URL 来自插件自动生成逻辑。2) 用户头像上传失败请检查：PHP gd 扩展是否可用上传文件格式是否为 JPG/PNG/GIF/WEBP上传文件大小是否超过插件设置阈值3) 设置页更新后样式或脚本不生效插件静态资源带版本参数（基于文件修改时间），如仍未更新，建议清理站点缓存和 OPcache。

Typecho OAuth 第三方登录插件 - AB OAuth
type: item
date: 2026-05-08T00:42:00+08:00
description: 这可能是史上颜值最高的 Typecho OAuth 第三方登录插件目录AB OAuthAdminBeautify 专用 OAuth 登录插件，支持QQ / 微信 / GitHub / Google / MSN / 新浪 / 豆瓣 / 百度 / OIDC等。精简显示完整显示OAuth 配置说明Github进入Github Developer Settings，左侧选择OAuth App，然后点击New OAuth App接着复制你的回调地址然后按照图片填入相关信息接着点击 generate client secret生成密钥将ClientID和生成的Client Secret分别填入AB-OAuth插件后台中即可Google进入Google API 控制台，点击进入OAuth 权限请求界面进入客户端，然后创建客户端填入相关客户端信息，选择Web 应用，并粘贴你的回调地址添加完成后弹出窗口将客户端ID和生成的客户端密钥分别填入AB-OAuth插件后台中即可Microsoft (MSN)进入Azure管理页面，点击进入Entry ID管理页面然后根据使用情况进行配置，粘贴您的回调地址，得到客户端ID进入证书与密码，添加新的客户端密码，其值为您的客户端密码检查API权限，是否有User.Read其他的正在编辑中

兰空图床对接超星学习通网盘 (支持多用户绑定)
type: item
date: 2026-04-27T23:51:00+08:00
description: 对接到的图床为 LHL's Images, 点击可跳转至图床开发思路先是在项目Misaka-1314/Chaoxing-MiniProgram的文档中看到了超星图床，觉得还挺好用，于是还是按照之前的一篇文章“图床外显为 Webdav 管理”的思路进行Webdav外显。注意到该项目中有些超星网盘的API(/docs/edge-functions/api/chaoxing/pan.js)以及上传图片的逻辑(/docs/.vitepress/components/ImageUpload.vue)，上传图片的逻辑已经搞定了。而由于国内网盘如果出现违规内容，则可能会封号，故现在只需考虑如何实现每个兰空图床用户绑定自己的超星账号。兰空图床对文件的命名支持魔法变量，其中涉及到用户的有{uid}，那么干脆指定文件名为{uid}-{md5}，这样既可以让Webdav端判断上传用户，又能避免文件名重复。建表CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, token TEXT UNIQUE, lsky_uid INTEGER, cx_username TEXT, cx_password_hash TEXT, cx_pan_token TEXT, cx_puid TEXT, cx_token_expires TEXT, created_at TEXT NOT NULL ); CREATE TABLE IF NOT EXISTS images ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL REFERENCES users(id), filename TEXT NOT NULL, original_name TEXT NOT NULL, md5 TEXT NOT NULL, size INTEGER NOT NULL, url TEXT NOT NULL, object_id TEXT, mime_type TEXT, uploaded_at TEXT NOT NULL );上传时逻辑：上传图片->判断UID是否绑定了超星账号->尝试上传到指定超星账号->上传成功以上步骤只要有一个为“否”，则会返回400用户绑定面板：https://chaoxing.img.lhl.one现在还需要解决兰空图床前台显示问题，如果直接在储存策略输出a标签则会转义输出导致无法输出超链接来提醒用户绑定超星账号，添加js脚本来解决这个问题 function fixEscapedHTML() { document.querySelectorAll('span').forEach(el => { if (el.innerHTML.includes('<a') && el.innerHTML.includes('')) { el.innerHTML = el.innerHTML .replace(/<a\s+href="([^"]+)"\s+targ?at="_blank">/gi, '') .replace(/<\/a>/gi, ''); } }); }还有一个问题，由于超星网盘开了防盗链，故需要在/user/photos 页面路由注册"no-referer" (这里参考之前的文章Lsky二次开发记录)RouteDOM.register({ route: '/user/photos', onEnter() { const existingMeta = document.querySelector('meta[name="referrer"]'); if (existingMeta) return true; const meta = document.createElement('meta'); meta.name = 'referrer'; meta.content = 'no-referrer'; meta.dataset.route = 'photos'; document.head.insertBefore(meta, document.head.firstChild); return true; }, onLeave() { const meta = document.querySelector('meta[name="referrer"][data-route="photos"]'); if (meta) meta.remove(); } });防盗链处理如果在全站使用，则…

内网穿透使用说明 (LHL's Shop专用)
type: item
date: 2026-04-21T11:58:00+08:00
description: 本产品使用NPS (yisier/nps) 0.26.32购买服务LHL's Shop客户端下载 LHL's Cloud 客户端安装对于Linux、Darwin快捷一键安装直接sudo ./npc后根据提示在对应的地方输入快捷启动命令亦可使用进程守护（pm2等）LHL's Shop 中给出的启动命令类似 ./npc -server=xxxxx.lhl.one:8024 -vkey=xxxxxxxx -type=tcp注意运行目录需要为 二进制文件npc所在目录，否则需要修改为绝对路径手动命令注册注册（启动命令添加install字样）：sudo ./npc install -server=xxxxx.lhl.one:8024 -vkey=xxxxxxxx -type=tcp启动：sudo npc start停止：sudo npc stop如果需要更换命令内容需要先卸载./npc uninstall，再重新注册对于Windows快捷一键安装以管理员身份打开npc.exe后，输入快捷启动命令启动下载GUI版本进行管理教程略手动注册服务对于windows，使用管理员身份运行cmd注册（启动命令添加install字样）：npc.exe install -server=xxxxx.lhl.one:8024 -vkey=xxxxxxxx -type=tcp启动：npc.exe start停止：npc.exe stop如果需要更换命令内容需要先卸载npc.exe uninstall，再重新注册隧道添加举个例子，现在添加UDP隧道作为SSH内网穿透，如图设置：看到分配的端口是16511那么访问地址则是xxxxx.lhl.one:16511 (xxxxx.lhl.one指服务连接信息中的服务器地址)Windows远程桌面3389VNC远程桌面5900网站创建添加域名解析，内网目标可以是https端口，如果不填写HTTPS证书和私钥，则仍使用原服务器的证书，填写则会代理证书。建议在您的服务器中打开强制https，否则代理端口最好是http端口(80)网站如果开启https后，内网目标建议填写443端口，并打开https重定向

Typecho Joe再续前缘v2 主题开心思路
type: item
date: 2026-04-10T23:08:00+08:00
description: 主题版本：v2.10 (Joe再续前缘) 作者：易航 (Yihang) 逆向：LHL逆向仅去除授权，可能有功能缺陷查看更多 Typecho 主题/插件逆向：跳转一、问题背景Joe再续前缘主题需要解决以下问题以实现纯本地运行：授权验证弹窗：主题内置域名授权验证，未授权时 PHP 直接 echo 提示文字数据库安装报错：主题重复激活时 ALTER TABLE ... ADD 报 Duplicate column name 致命错误API 路由 404：主题 /joe/api/* 接口全部返回 Path not found 错误点赞/收藏/关注按钮返回 HTML：AJAX 请求 API 但收到整页 HTML 而非 JSON二、主题加密架构分析2.1 识别加密文件首先查看主题文件结构，发现 public/ 目录下三个文件体积异常大且内容为乱码：ls -la public/ # common.php 59 KB # function.php 401 KB # api.php 341 KB用 hexdump -C 查看文件头，发现都以正常的 <?php 开头，随后跟随大量 goto 标签和变量赋值，这是典型的 PHP goto-based obfuscator 特征。核心数据存储在长字符串变量中，运行时通过 VM 解释器执行。2.2 确定 XOR 密钥通过对每个文件的数据区域进行频率分析，逐字节 XOR 尝试不同密钥（0x00-0xFF），检查解码结果是否产生可读文本：// 频率分析脚本 $file = file_get_contents('public/function.php'); for ($key = 0; $key < 256; $key++) { $readable = 0; for ($i = 5000; $i < 6000; $i++) { $c = ord($file[$i]) ^ $key; if ($c >= 32 && $c <= 126) $readable++; } if ($readable > 800) echo "key=0x" . dechex($key) . " readable=$readable\n"; }运行后输出：文件最佳密钥可读字符比例public/common.php0xB8 (184)约 85%public/function.php0xF2 (242)约 87%public/api.php0xBF (191)约 84%2.3 XOR 解码方法确定密钥后，使用以下方法解码指定偏移区间的字节：$file = file_get_contents('public/function.php'); $key = 242; // 0xF2 for ($i = $start; $i < $end; $i++) { $c = ord($file[$i]) ^ $key; if ($c >= 32 && $c <= 126) echo chr($c); else echo '.'; // 不可打印字符用 . 替代 }解码不会产生连续可读的 PHP 源码，而是产生夹杂 VM 操作码的片段。需要结合上下文辨认：字符串常量：连续 ASCII 字符，如 hash_hmac, sha256, auth.ini 等函数名/变量名：出现在 VM 调用指令附近结构边界：通过搜索 function、return、if 等关键字定位函数起止2.4 加密体系概览三个加密文件均采用 XOR 字节码 + goto 控制流 + 栈式虚拟机 架构：文件大小XOR 密钥职责public/common.php59 KB0xB8 (184)初始化常量、加载子文件public/function.php401 KB0xF2 (242)所有主题函数定义（含授权）public/api.php341 KB0xBF (191)JoeApi 类 API 接口加载链路：functions.php → require public/common.php common.php → require public/function.php (所有 joe_xxx 函数在此定义) common.php → require public/api.php (JoeApi 类在此定义)三、问题一：授权验证弹窗3.1 症状前台和后台页面均直接输出以下文字（非 JS 弹框，是 PHP echo）：欢迎您使用Joe再续前缘，请 赞助 后使用，联系方式：2136118039@qq.com3.2 逆向分析过程步骤 1：搜索错误文本来源在主题所有文件中 grep 搜索"赞助"、"auth.yihang"等关键字 → 仅在文件头注释中找到，非功能代码。确认消息来自加密 VM 运行时生成。…

Typecho Mirai 主题开心思路
type: item
date: 2026-04-08T22:11:00+08:00
description: 本文介绍的方法涉及关闭赞助版的校验流程，该做法可能绕过官方授权验证机制，仅供学习、测试或特殊场景下使用，请确保您拥有相关软件或服务的合法使用权。非法使用或未经授权的操作可能导致服务异常或法律风险，使用前请充分评估相关责任。本文主要目的是分享技术实现思路和代码示范，欢迎交流和探讨，严禁用于侵犯版权或违规用途。查看更多 Typecho 主题/插件逆向：跳转授权验证机制分析前言注意到lisence.php和loader.php两个文件被混淆编码了，且通过后台激活相关的POST请求定位到激活相关函数被加密（无法明文搜索到），但是返回内容判断已明文写出。整体流程functions.php └─ require core/loader.php ← 原始为加密混淆 VM 字节码 └─ 定义授权相关函数 common/init.php ├─ Mirai_licenseEnsureCoreLoaded() ← 若函数不存在则 HTTP 503 退出 ├─ Mirai_themeInit($archive) ← 初始化主题钩子 └─ Mirai_coreAuthEnforce() ← 许可强制检查点 core/license.php ← 二进制加密文件，由 loader.php 加载 core/auth-public.php ← 明文辅助函数（缓存/HTTP/弹窗渲染）验证函数清单（均由 loader.php 定义）此处内容需要评论回复后方可阅读Mirai_authGetStatus() 返回结构此处内容需要评论回复后方可阅读common/init.php 致命检查点// 原始代码：函数不存在时直接输出 503 并 exit if (function_exists('Mirai_licenseEnsureCoreLoaded')) { Mirai_licenseEnsureCoreLoaded(); } else { header('HTTP/1.1 503 Service Unavailable'); echo '...警告：非法篡改...'; exit; }本地运行改动修改的文件文件操作core/loader.php替换为 stub 实现，所有授权函数返回"已授权"core/license.php二进制文件替换为空 stub（原文件备份为 .bak）common/init.php移除函数不存在时的 503 致命退出分支core/loader.php stub 实现逻辑此处内容需要评论回复后方可阅读common/init.php 修改内容此处内容需要评论回复后方可阅读MiraiCore 插件说明MiraiCore 插件本身不含独立授权验证，其功能（订单、友链、Sitemap、爬虫记录等）完全依赖主题授权系统。替换 loader.php 后插件可正常激活使用。开心版下载此处内容需要评论回复后方可阅读写在最后原创不易，希望各位能够支持正版！正版购买入口：点我前往