Git 提交 GnuPG 自动签名

一般来说使用 git commit -S 就调用 gpg 工具自动搜索 user.name<user.email> 对应的私钥来签名提交。

git 2.0 以上版本提供了 commit.gpgsign 设置可以自动打开 gpg 签名选项。

然后配合 user.signingkey 就可以设置默认的 key 来自动签名了。

git config --global user.name "Larry Li"
git config --global user.email larryli@qq.com
git config --global user.signingkey 2D8B022C
git config --global commit.gpgsign true

密钥 2D8B022C 可以通过 gpg -K 查看可用的私钥。

WebSocket、API 与 Push 推送

WebSocket 从 2010 年出现到现在已经五六年了,目前来说主流浏览器已经对其普遍支持,但实际运行却非常之少。

一般来说,WebSocket 都是双向全双工通信的。所以很容易设计一个异步协议 WAMP,提供异步的 RPC 远程调用Publish & Subscribe 模式实现。

但是,这种设计完全无视了 WebSocket 是基于 HTTP 协议的。也就是说,HTTP 使用 url 来路由,WebSocket 也同样可以用 url 来路由。

就拿 Pub/Sub 模式来说,WebSocket 天生就可以使用不用的路由来表示不同的 Pub。

而浏览器作为 Client 去 Call 服务器不正是 RESTful API 该做的事情么?

那么,除非是服务器要去 Call 浏览器端,WAMP 的大部分设计都是不需要的。

WebSocket 真的只需要简单的使用,就如它一开始被赋予的使命一样,作为一个 Push 及时的把服务端最新的消息推送到客户端。甚至消息都不需要包含实体,而只是一个通知即可。

SSL 证书更新

一晃使用 StartSSL 免费证书已经好几年了。证书有效期只有一年,每年得提前两个星期来申请新证书更换旧的。

而且很坑的是,至今没有弄懂如何使用已有的私钥来申请新的证书。每次都是完整更新一次才罢。

据说这个月 Let’s Encrypt 就会开始提供全新的免费 SSL 证书方案。但目前为止除了月更的博客少的可怜几行文字外,都没什么可见的效果。

不过,这几年使用 SSL 的感受,其实加密的性能真的不是问题了。当然,对于 C10K 那种访问量来说,CPU 和内存开销当然不会少。

而且除开免费的 SSL 证书,一些收费证书的价格也不是那么高高在上的,

除开这些,SSL 真的很不错。

GitLab 汉化指南(安装/升级)

手工安装与升级

推荐按照 gitlab-ce 源代码中 doc/install/installation.md 的内容手工安装 GitLab 中文版本。

相关修改只需要在 Clone the Source 步骤中使用 https://gitlab.com/larryli/gitlab.git 仓库和当前版本的 7-13-zh 即可。

对于中国大陆境内的服务器用户,可以使用 https://git.coding.net/larryli/gitlab.git 镜像(镜像手工同步,比 gitlab.com 上略有延迟)。

另外也可以在 Install Gems 步骤中使用 https://gems.ruby-china.org/ 镜像加快 gems 安装。具体步骤如下:

cd /home/gitlab
sudo -u git -H bundle config mirror.https://rubygems.org https://gems.ruby-china.org/

# For PostgreSQL (note, the option says "without ... mysql")
sudo -u git -H bundle install --deployment --without development test mysql aws kerberos

# Or if you use MySQL (note, the option says "without ... postgres")
sudo -u git -H bundle install --deployment --without development test postgres aws kerberos

对于升级操作也可以按照相应的 update.md 类似处理即可。

官方推荐的 Omnibus 安装

请先使用官方包安装或升级完成,确认当前版本。

sudo cat /opt/gitlab/embedded/service/gitlab-rails/VERSION

并确认当前汉化版本的 VERSION 是否相同。

如果安装版本小于当前汉化版本,请先升级。如果安装版本大于当前汉化版本,请在本项目中提交新的 issue

如果版本相同,首先在本地 clone 仓库。

# GitLab.com 仓库
git clone https://gitlab.com/larryli/gitlab.git

# 或 GitCafe.com 镜像
git clone https://git.coding.net/larryli/gitlab.git

然后比较汉化分支和原分支,导出 patch 用的 diff 文件。

# 7.13 版本的汉化补丁
git diff origin/7-13-stable..7-13-zh > ../7.13.diff

然后上传 7.13.diff 文件到服务器。

# 停止 gitlab
sudo gitlab-ctl stop
sudo patch -D /opt/gitlab/embedded/service/gitlab-rails -p1 < 7.13.diff

确定没有 .rej 文件,重启 GitLab 即可。

sudo gitlab-ctl start

如果汉化中出现问题,请重新安装 GitLab(注意备份数据)。

如何干掉 Windows7/8 上的“获取 Windows 10”提示

如果还没看到,可以选择关闭自动更新,选择手动或者自动下载。在安装更新的时候跳过 KB3035583 即可。

否则的话,请点击“开始”菜单,再点击“控制面板”,找到“程序”下面的“卸载程序”。在左侧点击“查看已安装的更新”,在下面的“Microsoft Windows”组里面找到 KB3035583(如果发现的早,通常排在该组最上面)。右键“卸载”。

PuTTY 和 GitLab 的中文汉化版均更新到最新

从年后开始中断了三个月,终于恢复了。
期间因为 Google Code 的关闭,PuTTY 直接转移到 GitHub,同时也开始采用 GitLab 的本地化工作流
GitLab 跳过了好几个版本,包括一个未完成的 7.8 版本。其中 7.8 升级到 7.9 安装文档增加了 nodejs 的安装。
因为版本变动大,没有去跟踪变更,也没有仔细遍历文件。所以遗漏会很多。如果发现问题可以提交到 7.11的汉化里程碑中,会一直维护到下一个分支版本发布,也就是下个月 22 号。
这也希望能形成一种惯例。😁

Laravel 5 系统架构:服务提供者、服务容器、Contracts、Facades

官方文档在一方面真的写的很糟糕,完全没描述相互之间的关系。

事实上,服务提供者(Service Provider)服务容器(Service Container)ContractsFacades 是一件东西的多个方面。其实就是 Yii 的组件(Component)。

和 Yii 一样,Laravel 的所有功能都是通过与 Yii 组件类似的服务架构来实现的。

一个最简单直接的例子是 Lavarel Hashing 服务。其自身只是一个 Bcrypt hash 的封装。

首先,Laravel 5 定义了一个 Contracts:Illuminate/Contracts/Hashing/Hasher.php

<?php namespace IlluminateContractsHashing;
interface Hasher {
    /**
     * Hash the given value.
     *
     * @param  string  $value
     * @param  array   $options
     * @return string
     */
    public function make($value, array $options = array());
    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = array());
    /**
     * Check if the given hash has been hashed using the given options.
     *
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function needsRehash($hashedValue, array $options = array());
}

Contracts 只是描述一个服务的具体方法,而不是实现该服务。Container 才是服务的具体实现,对于一个服务来说,可能会有多种不同的实现。Hash 目前只有一个,就是:Illuminate/Hashing/BcryptHasher.php

<?php namespace IlluminateHashing;
use RuntimeException;
use IlluminateContractsHashingHasher as HasherContract;
class BcryptHasher implements HasherContract {
    /**
     * Default crypt cost factor.
     *
     * @var int
     */
    protected $rounds = 10;
    /**
     * Hash the given value.
     *
     * @param  string  $value
     * @param  array   $options
     * @return string
     *
     * @throws RuntimeException
     */
    public function make($value, array $options = array())
    {
        $cost = isset($options['rounds']) ? $options['rounds'] : $this->rounds;
        $hash = password_hash($value, PASSWORD_BCRYPT, array('cost' => $cost));
        if ($hash === false)
        {
            throw new RuntimeException("Bcrypt hashing not supported.");
        }
        return $hash;
    }
    /**
     * Check the given plain value against a hash.
     *
     * @param  string  $value
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function check($value, $hashedValue, array $options = array())
    {
        return password_verify($value, $hashedValue);
    }
    /**
     * Check if the given hash has been hashed using the given options.
     *
     * @param  string  $hashedValue
     * @param  array   $options
     * @return bool
     */
    public function needsRehash($hashedValue, array $options = array())
    {
        $cost = isset($options['rounds']) ? $options['rounds'] : $this->rounds;
        return password_needs_rehash($hashedValue, PASSWORD_BCRYPT, array('cost' => $cost));
    }
    /**
     * Set the default password work factor.
     *
     * @param  int  $rounds
     * @return $this
     */
    public function setRounds($rounds)
    {
        $this->rounds = (int) $rounds;
        return $this;
    }
}

除了实现 Contracts 中定义的三个方法外,还实现了一个额外 setRounds() 方法。

下一步就是注册为服务提供者了:Illuminate/Hashing/HashServiceProvider.php

<?php namespace IlluminateHashing;
use IlluminateSupportServiceProvider;
class HashServiceProvider extends ServiceProvider {
    /**
     * Indicates if loading of the provider is deferred.
     *
     * @var bool
     */
    protected $defer = true;
    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton('hash', function() { return new BcryptHasher; });
    }
    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        return array('hash');
    }
}

很明显的 register 了服务,具体做的就是 new 了一个 Container。如果容器有多种实现,这时建议使用 Config 来配置服务了。

$this->app->singleton('hash', function($app) { return new Hasher($app['config']['hash']); });

这时候 Hasher 实际上一个工厂类(Factory),使用配置来确定具体的,如 new Hasher('bcrypt') 来实例化。

如果服务要延迟载入,也就是按需载入。需要有一个激活标志,也就是 provides() 方法。

当然,HashServiceProvider.php 必须在 config/app.phpproviders 中定义 'IlluminateHashingHashServiceProvider' 行。

这时,就可以使用:

$this->app->make('hash')->make('password');
$this->app['hash']->make('password');

最后,声明一个 Facade:Illuminate/Support/Facades/Hash.php

<?php namespace IlluminateSupportFacades;
/**
 * @see IlluminateHashingBcryptHasher
 */
class Hash extends Facade {
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'hash';
    }
}

config/app.phpaliases 中定义 'Hash' => 'IlluminateSupportFacadesHash' 行。

那么,就不用上面长长的 $this->app->make('hash'),直接:

Hash::make('password');

清除 chrome 的 HSTS 307 缓存

现代浏览器和网页服务器都开始支持 HSTS 功能,即自动将不安全的 HTTP 请求使用 307 Internal Redirect 跳转到 HTTPS 请求。

但是,用户的第一次访问还是不安全的。简单的说,在发生 307 的时候,用户可能就已经将用户名和密码暴露了。因为此时还是 HTTP 请求。

而且,这个第一次还可能是每次浏览器启动的时候,也就是说,可能每天都会发生,甚至多次。

所以,chrome 会自动记住每个域的 HSTS 设置。使得 HSTS 只是理论上的第一次暴露,后来就不经网页服务器返回,浏览器查询本地数据,直接伪造 HSTS 307 跳转到安全的 HTTPS,避免敏感数据的暴露。

很遗憾的说,这个很贴心的功能有时会造成麻烦。也就是说,一旦网页服务器设置了 HSTS,浏览器记住了。那么,将不会再访问该域的 HTTP 了。即使是网页服务器端已经修改了相关配置。原因当然是,这个记住是浏览器本地的。

还好,chrome 有暴露一些内部信息。不然就只有彻底删除浏览器才能清除。。。

在地址栏打开 chrome://net-internals/#hsts 下方的 Query domain 可以查询指定的域是否有 HSTS 记录,存在的话,在 Delete domain 删除即可。