为何 shadowsocks 要弃用一次性验证 (OTA)

前些天,shadowsocks 提出了 SIP004 草案,旨在使用 AEAD 算法 取代原先的不安全的 流加密 + OTA,并弃用了一次性验证 (OTA)。

新协议的提出对于 shadowsocks 是一个非常非常重大的改进,因此我写了这篇博文为看不懂洋文的友们科普一下「为什么 OTA 会被这么快被弃用」以及「为什么应该使用新协议」。

一、OTA 是什么

OTA(One Time Auth,一次性验证),是之前 shadowsocks 为了增强安全性,抵抗 CCA(Chosen-ciphertext Attack,选择密文攻击)而加入的实验性功能。

我觉得应该很多人都听过这玩意 —— 就算不知道 OTA 是啥好歹也在 shadowsocks 各分支的客户端上看到过「一次性验证」的开关吧?虽然这个名字确实起得有点让人不明所以就是了(笑)。

那么下面我来科普下当初为什么要加入 OTA 功能。

阅读全文→

我的 2016 年终总结

人生天地之间,若白驹之过隙,忽然而已。——《庄子·知北游》

又到了写年终总结的时候了,时间过得真鸡儿快啊。虽然没有 Maxine Caulfield 那样操控时间轴的能力,但是回顾一下我在 2016 的大事件的能力还是有的:

概览

过去的一年里,本博客的基本访问情况如下图:

Google Analytics Overview

这期间,本博客一共迎来了 36,637 位用户,他们一共产生了 56,667 次会话以及 96,728 次浏览。平均每天 100 位用户、155 次会话以及 265 次浏览。

阅读全文→

博客启用新域名 Blessing.Studio

原来的域名 prinzeugen.net 一直被人吐槽说不好记,但苦于没有什么中意的其他的好记的域名,所以换域名的计划就一直搁置着。

其实我以前就听说过 .studio 这个顶级域名了,但是当时(15 年中旬)还没有开放注册,所以后来也就忘却了它的存在。然而几天前在机缘巧合下我得知了它早在 2015.10 就已经开放注册了,并且现在一年只要百来块就能搞到,于是。。

QQ20161224205054.png

这也是没有办法的事情嘛~ QQ20161225134536.jpg

そういうわけで、博客要迁移至新域名 blessing.studio 啦~

目前 prinzeugen.net 已经 301 至新域名,并且提交了 Google Search Console 和 Disqus 评论的转移请求,估计过个一天可以迁移完毕。

嗯?你说 .studio 不能备案,对百度 SEO 不好?

Who cares. QQ20161225135139.jpg

阅读全文→

Laravel 使用 whoops 处理错误最优雅的姿势

filp/whoops 这个错误处理类库有什么好处我这里就不赘述了,谁用谁知道。

Laravel 在 4.x 时代是有集成了 whoops 的,但是在 5.x 去掉了。不过作为一个 out-of-the-box 的错误处理类库,我们依然可以很方便地将 whoops 带回 Laravel 中。

网上有很多文章都讲述了 Laravel 使用 whoops 的方法,但总有些小问题(像是代码太丑了啊,代码太丑了啊之类的)。其中我认为最优雅的实现是这篇文章所描述的:Bringing Whoops Back to Laravel 5,我下面的也是基于他给出的代码修改的。


安装 whoops 之类的步骤我这里就不说了,这些在它的 README 上都有。安装完后打开 app/Exceptions/Handler.php 这个文件,进行如下修改:

/**
 * Render an exception into an HTTP response.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Exception  $e
 * @return \Illuminate\Http\Response
 */
public function render($request, Exception $e)  
{
    if ($e instanceof
阅读全文→

手动修改 Laravel url() 函数生成的 URL 中的根地址

大家都晓得 Larevel 的一票帮助函数中有个 url(),可以通过给予的目录生成完整的 URL,是非常方便的一个函数:

// return: https://skin.dev/user/profile
url('user/profile')  

但是这玩意生成的 URL 中要补完的部分是框架内部根据 Request 自动判断的,而自动判断出的东西有时候会出错(譬如在套了一层反向代理之类的情况下)。

文档上并没有提到我们要如何才能自定义它生成的 URL 中的根地址和协议头部分(http(s)),这就非常吃瘪了。那我们要咋办呢?

首先我们来看看 url() 被定义的位置:

# File: src/Illuminate/Foundation/helpers.php

/**
 * Generate a url for the application.
 *
 * @param  string  $path
 * @param  mixed   $parameters
 * @param  bool    $secure
 * @return Illuminate\Contracts\Routing\UrlGenerator|string
 */
function url($path = null, $parameters = [], $secure = null)  
{
    if (is_null($path)) {
        return app(UrlGenerator::class);
    }

    return app(UrlGenerator::class)-&
阅读全文→

Artisan::call('migrate') 在 APP_ENV 为 production 时不工作的解决方法

最近把版本库里 .env.exampleAPP_ENV 字段值从原来的 local 改为了 production,原意是为了更好的区分开发和生产环境。

然而今天在主机壳的虚拟主机上测试我的程序的时候(准备把演示站搬过去),却出现了奇怪的问题——数据库 Migration 不管用了。

我是在控制器里通过调用 Artisan::call('migrate') 来执行数据库迁移操作的(毕竟虚拟主机哪来的 shell 访问),但是这次这条命令竟然没有执行任何事务。

通过 Artisan 执行 Command 的简化流程大概是像这样的:

Illuminate\Foundation\Console\Kernel  
↓
Illuminate\Console\Application  
↓
Illuminate\Console\Command  
↓
Illuminate\Container\Container  
↓
// 这个就是执行 Artisan::call('migrate') 时调用的类
Illuminate\Database\Console\Migrations\MigrateCommand  
↓
……

经过一段时间的排查,最后锁定了是在 MigrateCommand 这个类停止继续往下执行的,即接下来的脚本都没有被执行到,也就是说问题就出在 MigrateCommand 这里。

阅读全文→

使用 Certbot 更新 Let's Encrypt 证书

Let's Encrypt 证书即将过期时会给你发送邮件,这个还是比较贴心的。这样也就不会陷入证书过期却没发现的尴尬境地(Let's Encrypt 的证书只有 90 天的有效期)。

2826714bc9645e4b9828433b8e674800.png

以前我写过使用 Certbot 这个工具申请证书的文章,而同样使用这个工具更新证书只需要一行命令:

certbot renew --post-hook "service nginx reload"  

certbot 这个脚本的位置呀名称啥的自己看着改,对于我来说是 ./certbot-auto。加了个钩子可以让它在证书更新更新完毕后重载 Nginx 配置来更新证书。

b2134999636066c29c9e93a40bd88a57.png

不想每次都登上去更新的也可以把上面那行脚本加入 crontab(crontab -e),让它每个月执行一次:

# 这里用绝对路径,保险一点
0 0 1 * * /home/xxx/certbot-auto renew --post-hook "service nginx reload" >/dev/null 2>&1  

P.S. Xshell 管理远程机子比起单纯的终端来还是很方便的,而且最近也对 Home/School 发放免费许可了。

参考链接:Renewing certificates - Certbot User Guide

阅读全文→

PHP 远程文件下载的进度条实现

PHP 实现远程下载文件到服务端并不是什么新鲜玩意,用 cURLfile_get_contentsfopen 等都能够轻易实现。

但是这几种常规的方法都是在一个线程内下载文件,等文件下载完毕以后才能返回 HTTP 响应。所造成的结果就是用户在页面上点击「下载到服务器」按钮后,会看到空白页和加载的小菊花转啊转,转好久之后才出现「下载成功」的页面。

当然,我上面所举例的情况是只使用纯粹的表单 POST 发送请求的情况。现在的话就算再不济也一般会使用 ajax 发送请求,然后在前台放个加载动画,等收到下载成功的回应之后再进行下一步操作。

但是!即使是去掉了恶心的且需要等待的空白页,这样做还是对用户体验有不好的影响。没有具体的下载进度,只有一个一直转呀转的菊花图,估计挺多用户都无法坐和放宽吧(至少对于我来说是这样的)

而我一个 PHP 项目的一键更新系统正好需要重构,遂研究了如何在 PHP 作为后端时显示远程文件下载进度条,并捣鼓出了个像样的解决方案,在这里分享一下。

阅读全文→

耳机插头修理技巧

群里大佬 pan爷低价出了我一个耳机插头附近断线的 ATH-ES55,这已经是挺久以前的事了。当时我去某宝上买了个耳机插头,刮掉耳机线的漆包草草焊上去就完事了(好歹是挺不错的耳机你就这样对待啊喂)。然而最近耳机插头接触不良了,我就寻思着重新焊下,在这里记录一下需要注意的地方。

虽然修耳机这种事我在小学的时候就鼓捣过了,但总归当时还是不专业,也没啥像样的工具。而且最近听的好歹也算是 HiFi 耳机,不能再用之前那种乡巴佬方法了(笑)。在网上搜了一些,学到了不少,在此记录一下。

下面几乎都是盗图,侵删w

3.5mm 耳机插头接线图

82f3a4e9e890e1d4ab91352def12f33a.png

阅读全文→

Laravel 框架下的插件机制实现(一)—— 构建插件系统

插件,即 Plug-in(又有外挂、Extension、Addon 等叫法),是一类特定的功能模块,通过和应用程序的互动,用来替应用程序增加一些所需要的特定的功能。插件的特点是:

  • 当你需要它的时候激活它,不需要它的时候禁用/删除它;
  • 无论是激活还是禁用都不影响系统核心模块的运行。

也就是说插件是一种非侵入式的模块化设计,实现了核心程序与插件程序的松散耦合。上面的介绍部分摘自 中文 WikiPedia

虽然现在网上有很多 PHP 的插件机制的实现(当然我指的是英文内容,中文关于 PHP 插件机制的搜出来现在还是那么点破文章),譬如 FoolCode/Plugin,或者 WordPress 的插件实现。

不过我今天想介绍的是如何使用 Laravel 的服务容器、事件机制等功能来实现一个比较优雅的插件机制。

Greatly inspired by Flarum,在此致谢 ヾ(´ω゚`)

阅读全文→