https://rubicon.lightstands.xyz
Rubicon's Rubicon • Posts by "logbook" tag
2021-12-30T13:26:06.000Z
https://rubicon.lightstands.xyz/2021/12/30/Blog-2021-Final-Update/
博客2021年最终功能更新
<p>我对博客功能的要求是拒绝花里胡哨,一切为阅读服务。现在是2021年年底,正好我要为我对年终总结的一些设想给博客更新一些功能:快速引用素材、Steam游戏卡片、引用Wikipedia条目。</p>
<span id="more"></span>
<h2 id="快速引用素材"><a href="#快速引用素材" class="headerlink" title="快速引用素材"></a>快速引用素材</h2><p>之前我引用图片一直都是用图片的完整路径,实在是非常麻烦,所以我一直期待能找到一个简单的方法引用素材。原先的考虑是用<a href="https://github.com/cnzsb/hexo-asset">hexo-asset</a>,但是在一番简单搜索后发现hexo-render-marked在3.1.0+已经携带了类似功能了:<a href="https://hexo.io/docs/asset-folders.html#Embedding-an-image-using-markdown">https://hexo.io/docs/asset-folders.html#Embedding-an-image-using-markdown</a> 。直接在_config.yml里打开就行。</p>
<figure class="highlight yaml"><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="attr">post_asset_folder:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr">marked:</span></span><br><span class="line"> <span class="attr">prependRoot:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">postAsset:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure>
<p><img src="/2021/12/30/Blog-2021-Final-Update/mastodon_Elephant_Friend_Curious.png" alt="测试用的可爱Mastodon"></p>
<h2 id="Steam游戏卡片"><a href="#Steam游戏卡片" class="headerlink" title="Steam游戏卡片"></a>Steam游戏卡片</h2><iframe src="https://store.steampowered.com/widget/22380/" frameborder="0" width="100%" height="190"></iframe>
<iframe src="https://store.steampowered.com/widget/412020/?t=《地铁:离乡》确实是非常不错的半开放世界线性流程FPS。" frameborder="0" width="100%" height="190"></iframe>
<p>搜刮到<a href="https://github.com/HCLonely/hexo-tag-steamgame">hexo-tag-steamgames</a>可以实现这个。</p>
<h2 id="引用Wikipedia条目"><a href="#引用Wikipedia条目" class="headerlink" title="引用Wikipedia条目"></a>引用Wikipedia条目</h2><blockquote>undefined<p><a href="https://zh.wikipedia.org/wiki/Wikipedia">Wikipedia:Wikipedia</a></p></blockquote>
<p>原来我是想用<a href="https://github.com/tuanna-hsp/hexo-tag-wikipedia">hexo-tag-wikipedia</a>。但是:</p>
<ol>
<li>这个插件用的不是新的Restful API,实际获取到的字符串千奇百怪。</li>
<li>这东西一开始用不了,我一看控制台发现一串<code>$.getJSON</code>:它插入的脚本用的JQuery的API。然而我的网页上并没有JQuery。</li>
</ol>
<p>最后我改了一下把它改成用XMLHTTPRequest从<a href="https://en.wikipedia.org/api/rest_v1/#/">Wikipedia的Restful API</a>拉取数据。脚本很简单:</p>
<figure class="highlight zephir"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">buildArgsHash</span><span class="params">(args)</span> </span>{</span><br><span class="line"> <span class="keyword">let</span> argsHash = {};</span><br><span class="line"> args.forEach(arg => {</span><br><span class="line"> <span class="keyword">const</span> params = arg.split(<span class="string">':'</span>);</span><br><span class="line"> argsHash[params[<span class="number">0</span>]] = params[<span class="number">1</span>];</span><br><span class="line"> });</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> argsHash;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">generateWikipediaTagHtml</span><span class="params">(args, content)</span> </span>{</span><br><span class="line"> <span class="keyword">const</span> argsHash = buildArgsHash(args);</span><br><span class="line"> <span class="keyword">const</span> title = argsHash[<span class="string">'title'</span>];</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> lang = argsHash[<span class="string">'lang'</span>] !== <span class="keyword">undefined</span> ? argsHash[<span class="string">'lang'</span>] : <span class="string">'en'</span>;</span><br><span class="line"> <span class="keyword">const</span> baseUrl = `https:<span class="comment">//${lang}.wikipedia.org`;</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> url = `${baseUrl}/api/rest_v1/page/summary/${title}?redirect=<span class="keyword">false</span>`;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">const</span> tagId = Math.round(Math.random() * <span class="number">100000</span>);</span><br><span class="line"> <span class="keyword">const</span> embeddedScript = `</span><br><span class="line"> window.addEventListener(<span class="string">'load'</span>, <span class="function"><span class="keyword">function</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">var</span> element = document.getElementById(<span class="string">'${tagId}'</span>);</span><br><span class="line"> <span class="keyword">var</span> req = <span class="keyword">new</span> XMLHttpRequest();</span><br><span class="line"> req.addEventListener(<span class="string">"load"</span>, <span class="function"><span class="keyword">function</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">var</span> result = this.response;</span><br><span class="line"> <span class="keyword">const</span> extract = result.extract;</span><br><span class="line"> element.prepend(extract);</span><br><span class="line"> });</span><br><span class="line"> req.addEventListener(<span class="string">"error"</span>, <span class="function"><span class="keyword">function</span><span class="params">()</span> </span>{</span><br><span class="line"> element.prepend(<span class="string">'Failed to fetch wikipedia data for "${title}".'</span>);</span><br><span class="line"> });</span><br><span class="line"> req.open(<span class="string">'GET'</span>, <span class="string">'${url}'</span>);</span><br><span class="line"> req.responseType = <span class="string">'json'</span>;</span><br><span class="line"> req.setRequestHeader(<span class="string">'accept'</span>, <span class="string">'application/json; charset=utf-8; profile="https://www.mediawiki.org/wiki/Specs/Summary/1.4.2"'</span>);</span><br><span class="line"> req.send();</span><br><span class="line"> });</span><br><span class="line"> `;</span><br><span class="line"> <span class="keyword">let</span> contentText = `<script>${embeddedScript}</script>`;</span><br><span class="line"> <span class="keyword">if</span> (argsHash[<span class="string">'wikiButton'</span>] === <span class="string">'true'</span>) {</span><br><span class="line"> contentText += `<p><a href=<span class="string">"${baseUrl}/wiki/${title}"</span>>Wikipedia:${title}</a></p>`;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> `<blockquote id=<span class="string">'${tagId}'</span>>${contentText}</blockquote>`;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">hexo.extend.tag.register(<span class="string">'wikipedia'</span>, generateWikipediaTagHtml);</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>我把它塞到了我的fork里( <a href="https://github.com/thislight/hexo-tag-wikipedia">https://github.com/thislight/hexo-tag-wikipedia</a> ),找时间我可能问问作者再把它合并到上游,因为有一个breaking change。我打算后面把它改成在服务器上获取,这样动态插入一大段文字的体验挺糟糕,而且每一个访客都要获取一次有点滥用资源的意思。</p>
2021-12-30T13:26:06.000Z
https://rubicon.lightstands.xyz/2021/07/10/set-up-sudo-with-howdy-on-fedora-34-for-faical-authenticating/
在Fedora 34上通过Howdy为sudo增加人脸识别认证
<p>今天晚上折腾了一个小时,终于把 Howdy 折腾出来了,写篇博文作笔记以备查。</p>
<p><a href="https://github.com/boltgolt/howdy">Howdy</a> 是一个为 Linux 提供 Windows Hello 风格验证的软件,它作为一个 PAM 模块为其它软件提供人脸验证服务。不像 Windows Hello 需要认证过的IR摄像头, Howdy 基本上只要是个摄像头都可以使用。当然,如果没有 IR ,低光环境下的识别率就很拼摄像头的素质了。</p>
<p>这篇博文主要内容是给 sudo 弄 Howdy:sudo 老是让人输密码着实令人烦躁,但是我又不想取消所有认证,正好 Howdy 的需求很低(只需要一个摄像头)。</p>
<span id="more"></span>
<p>我机器上使用的发行版是 Fedora 34,64 位。</p>
<h2 id="安装Howdy"><a href="#安装Howdy" class="headerlink" title="安装Howdy"></a>安装Howdy</h2><p>只需要跟随 Howdy 项目的 README 里的步骤就可以安装 Howdy 了:</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo dnf copr enable luya/howdy</span><br><span class="line">sudo dnf install howdy</span><br></pre></td></tr></table></figure>
<p>然后就按照 README 上面的说法执行 <code>sudo howdy add</code> 添加面孔,然后就看见显示 <code>pip3 show dlib</code> 之类的错误信息,意思是找不到 dlib 。这个 copr 仓库里的包没有把 dlib 作为依赖,得自己安装。</p>
<p>可以用 <code>sudo dnf install python-dlib</code> 安装dlib。也可以用pip安装: <code>sudo pip install dlib</code> ,但是编译的时候肯定会卡几分钟,并且大概会占用 2-3GB 左右的内存。</p>
<p>接下来再次运行 <code>sudo howdy add</code> ,它会抱怨摄像头路径还没配置好:</p>
<figure class="highlight pgsql"><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></pre></td><td class="code"><pre><span class="line">[sudo] <span class="keyword">password</span> <span class="keyword">for</span> ***: </span><br><span class="line">Adding face model <span class="keyword">for</span> the <span class="keyword">user</span> ***</span><br><span class="line">Enter a label <span class="keyword">for</span> this <span class="built_in">new</span> model [Initial model] (max <span class="number">24</span> characters): </span><br><span class="line">Camera <span class="type">path</span> <span class="keyword">is</span> <span class="keyword">not</span> configured correctly, please edit the <span class="string">'device_path'</span> config <span class="keyword">value</span>.</span><br><span class="line"><span class="keyword">Exception</span> ignored <span class="keyword">in</span>: <<span class="keyword">function</span> VideoCapture.__del__ at <span class="number">0x7f855eeb1b80</span>></span><br><span class="line">Traceback (most recent <span class="keyword">call</span> last):</span><br><span class="line"> File "/usr/lib64/security/howdy/recorders/video_capture.py", <span class="type">line</span> <span class="number">55</span>, <span class="keyword">in</span> __del__</span><br><span class="line"> self.internal.<span class="keyword">release</span>()</span><br><span class="line">AttributeError: <span class="string">'VideoCapture'</span> <span class="keyword">object</span> has <span class="keyword">no</span> <span class="keyword">attribute</span> <span class="string">'internal'</span></span><br></pre></td></tr></table></figure>
<p>运行 <code>sudo howdy config</code> 来打开配置,默认情况下会使用 GNU nano 作为编辑器。找到 <code>device_path = </code> 这一行,我们要设置的就是这个值。但是怎么知道是哪个路径呢?我用的是VLC里面的”Open Capture Device…”:将”Capture mode”设为”Video camera”,在”Video device name”的下拉菜单里面的选项选择一个,点”Play”。一个一个地尝试不同的选项,哪个有画面就是哪个路径。在我的机器上,这个路径是 <code>/dev/video0</code> ,最后就是 <code>device_path = /dev/video0</code> 。</p>
<img src="/img/set-up-sudo-with-howdy-on-fedora-34-for-faical-authenticating/vlc-open-capture-device.png" class="" title="图片里的最后一个选项:Open Capture Device...,点击之后会打开一个窗口">
<p>配置好之后运行 <code>sudo howdy add</code>增 加面孔,这下能够顺利增加了!增加完面孔可以用 <code>sudo howdy test</code> 打开测试窗口进行测试。</p>
<h2 id="配置PAM"><a href="#配置PAM" class="headerlink" title="配置PAM"></a>配置PAM</h2><p>PAM ,或者叫 Pluggable Authentication Module ,是一个中心化的身份验证服务。<a href="https://www.redhat.com/sysadmin/pluggable-authentication-modules-pam">这里有一篇对PAM的介绍</a>。</p>
<p>参考 <a href="https://wiki.archlinux.org/title/Howdy">Arch Wiki上的Howdy词条</a>,要配置 sudo 的验证时行为,只需要修改 <code>/etc/pam.d/sudo</code> ,在原先的第二行前面再加一行:</p>
<figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">auth sufficient pam_python.so <span class="regexp">/lib64/</span>security<span class="regexp">/howdy/</span>pam.py</span><br></pre></td></tr></table></figure>
<p>这里用<code>/lib64</code>替换了 Arch Wiki 词条上的<code>/lib</code>,是因为提供给 Fedora 的这个包把这些文件安装到<code>/lib64</code>而不是<code>/lib</code>,这个地方各个发行版可能都有不同的规则。</p>
<p>PAM 的配置在修改后会自动应用。现在我们可以试试使用<code>sudo -i</code>看看有没有调用人脸识别:</p>
<figure class="highlight angelscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">[sudo]</span> password <span class="keyword">for</span> ***:</span><br></pre></td></tr></table></figure>
<p>事情变得奇妙了起来……Howdy 并没有被调用。这说明 PAM 配置哪里出了问题,读一读跟 PAM 有关的日志:</p>
<figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">sudo journalctl -g pam -r</span></span><br></pre></td></tr></table></figure>
<p>然后发现了奇妙的错误:</p>
<figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">PAM adding faulty module: <span class="regexp">/lib/</span>security/pam_python.so</span><br><span class="line">PAM unable to dlopen(<span class="regexp">/lib/</span>security<span class="regexp">/pam_python.so): /</span>lib<span class="regexp">/security/</span>pam_python.so: cannot open shared object <span class="keyword">file</span>: No such <span class="keyword">file</span> or directory</span><br></pre></td></tr></table></figure>
<p>原来是找不到指定的 pam_python.so 这个 PAM 模块(用来调用 Howdy 的 pam.py ,Howdy 提供的 pam.py 是一个 Python 文件)。</p>
<p>还好 <a href="https://copr.fedorainfracloud.org/coprs/luya/howdy/">luya/howdy Copr仓库</a> 下的评论给我找到了一个简单的出路:根据 [RPM Sphere网站] 上的流程安装了 RPM Fusion 和 RPM Sphere 这两个第三方软件源之后,可以在 RPM Sphere 这个软件源上找到<code>pam_python</code>这个包:</p>
<figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dnf <span class="keyword">install</span> pam_python</span><br></pre></td></tr></table></figure>
<p>然后就可以愉悦地使用了!</p>
<figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo -<span class="selector-tag">i</span></span><br></pre></td></tr></table></figure>
<h2 id="使用pamtester测试"><a href="#使用pamtester测试" class="headerlink" title="使用pamtester测试"></a>使用pamtester测试</h2><p><a href="http://pamtester.sourceforge.net/">Pamtester</a> 可以测试 PAM 的指定验证服务,这样要检查 Howdy 是否生效或者单纯享受人脸识别(大雾)就很简单啦。</p>
<figure class="highlight cmake"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dnf <span class="keyword">install</span> pamtester</span><br></pre></td></tr></table></figure>
<p>在这篇文章的例子里只需要(用要验证的用户的用户名代替<code><用户名></code>)</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pamtester sudo <span class="tag"><<span class="name">用户名</span>></span> authenticate</span><br></pre></td></tr></table></figure>
<p>就可以触发 PAM 的验证了。</p>
2021-07-10T14:34:29.000Z