#830 关于 Linux 发行版

2022-08-28

发行版

  • Minix
  • Unix 阵营
  • 闭源
    • HP-UX
    • Solaris
    • AIX
    • macOS
  • 开源
    • FreeBSD
    • NetBSD
    • OpenBSD
    • DragonFly BSD
  • Linux 阵营
  • Android (AOSP)
    • LineageOS
  • Debian
    • Ubuntu
  • RedHat
    • CentOS
  • OpenSUSE
  • Gentoo
  • Arch Linux
    • Manjaro

Debian / Ubuntu 和 RHEL / CentOS 衍生版本太多,就不列了。
我们常见的 Linux 发行版应该差不多都能找到自己的位置。

桌面环境

图形库主要就是两种:GTK,Qt

  • 基于 GTK
  • GNOME
  • Xfce
  • Cinnamon
  • MATE
  • LXDE
  • Unity:ubuntu
  • Budgie
  • 基于 Qt
  • KDE Plasma
  • LXQt
  • Deepin Desktop Environment (DDE)
  • UKUI:ubunty kylin

个人看法

  1. 在国际关系越来越趋于对抗的这个局面下,Linux 对于中俄等国都有战略安全的重要作用。
  2. 国产 Linux 系统厂商大有搞头。
  3. 关于国产系统:
    1. 国产 Linux 桌面只有 Deepin 可以一战,而且做了太多工作,应该得到尊敬。
    2. 国产服务器系统我一个都没有用过,不知道如何。
  4. Unix 系统的生态和 Linux 完全不是同一个级别。
  5. 除非有特别的原因,否则应该直接选择 Linux。
  6. Deepin 等国产 Linux 系统提供商想搞什么国产根系统,想切断和社区的关联,在我看来是非常愚蠢的。
  7. 反而应该加大对社区的投入。
  8. 如果不知道该选哪个 Linux 发行版,我的建议是 Ubuntu。
  9. 无论是服务器还是个人使用,都可以直接选择上一个版本 Ubuntu LTS
  10. 如果比较喜欢尝鲜,个人使用可以选最新版本 Ubuntu
  11. 如果对 Ubuntu snap 不满意,就选择 Debian。
  12. 如果问选哪个桌面环境,就选 GNOME
  13. KDE 我没有用过,不知道
  14. 选 GNOME 作为默认桌面的多,应该是有道理的
  15. 桌面并没有那么重要,方便快捷的命令行操作才是 Linux 精髓
  16. 如果对发行版不满,就在基准系统上通过增删组件达成自己的目的,不要觉得换一个系统就能完美解决问题。
  17. 如果有时间折腾不同的发行版,还不如去玩一会儿游戏。

#829 HTTP/2 的几个特性

2022-08-20
  • Server Push 服务器主动推送资源,客户端请求 A 的时候,服务器把 A 相关的资源 B, C, D 都一起推送给客户端。
  • Early Hints HTTP 103 状态码。客户端请求 A 的时候,

    1. 如果是普通情况,服务器返回 200 状态码,带上资源信息
    2. 如果应用上 Early Hints,服务器返回 103 状态码,带上需要资源信息(Link 头),然后是资源信息

    好处就是节省了浏览器解析 HTML 获取子资源信息的延迟。刚解析 103 头,就可以开始请求子资源了。
    就最近的几个月,主流浏览器开始提供支持。

  • Preload Critical Assets 就是 HTML link 头中的 rel="preload",提前加载文件,避免按照文件解析生成的调用链顺序来加载,而提升资源加载速度。

Chrome 将禁用 HTTP/2 服务器推送(Server Push)支持

谷歌博客显示,在 Chrome 106 和其他基于 Chromium 的浏览器的下个版本中,默认情况下将禁用对 HTTP/2 服务器推送(HTTP/2 Server Push)的支持。

HTTP/2 允许服务器在实际请求之前 “推送” 服务端可能需要的资源, HTTP/2 的 Server Push 特性解决了 HTTP/1.x 的无脑按顺序加载资源的问题,本意是提高网页的响应性能。

然而这功能逻辑本身就有问题,比如资源存放在单个业务服务器上,并行推送多个静态资源只会降低响应速度,性能不升反降。而对于前后端分离的业务来说,HTTP/2 本身就支持多路复用,server push 只能稍微降低浏览器解析 html 的时间,对现代浏览器来说性能提升可以忽略不计。

HTTP/2 时代也只有 1.25% 的 HTTP/2 站点使用了这个特性。在 HTTP/3 出来之后,该功能更是彻底被遗忘了,最新的分析中,网站对 HTTP/2 的支持率从 1.25% 下降到 0.7%。

替代方案

103 Early Hints  是 Server Push 的首选替代方案,它具有 Push 的许多优点,而缺点则少得多。与服务器推送资源不同,103 Early Hints 只向浏览器发送可能受益于请求的资源提示。浏览器可以控制它是否需要这些资源,比如浏览器已经在 HTTP 缓存中拥有这些资源,则无需额外加载。

预加载关键资源是另一种选择,它允许页面和浏览器一起工作,在页面加载的早期抢先加载关键资源。它不如 Server Push  或 Early Hints   快 —— 但它不会延迟关键页面资源,而另外两种解决方案都可能发生这种情况。

参考资料与拓展阅读

#828 代码中的 TODO 注释

2022-08-19

Stop Using TODO for Everything》建议采用更加明确的标记来注释代码:

  • FIXME/BUG 需要修复(缺陷)
  • CHECKME/REVIEW 需要审查
  • DOCME 需要文档
  • TESTME 需要测试
  • HACK/OPTIMIZE 需要优化

我就是喜欢在代码中写 TODO,以后可以照着这个建议搞些花样。

#827 2FA:双因素身份认证

2022-08-19

2FA / MFA

双因素 / 多因素认证,就是指处理密码之外,再加一些辅助手段用来加强认证。

常见的 2FA 方式:

  1. 密码 + 短信验证码
  2. 密码 + 微信公众号推送验证码
  3. 密码 + 身份验证器
  4. 密码 + U盾

人体特征

应该有人脸,指纹,声纹,虹膜等方式的组合(甚至在异形 4 中有吹气的方式),这些在我们的数字生活中这些认证方式多少都有一些体验吧。

动态口令卡

事先给客户一张密码表,然后需要的时候要求客户按要求输入指定位置的数字用来验证身份。

原理应该和微信让用户指认哪个头像是自己的好友一样。

证书

银行的 U 盾

OTP(动态密码)

一次性密码,One Time Password

TOTP 的全称是"基于时间的一次性密码"(Time-based One-time Password)。它是公认的可靠解决方案,已经写入国际标准 RFC6238。

不知道密码学上是什么原理,只知道可以每分钟生成一个 6 位密码。只要双方算法和密钥一致,就能实现认证。

软件的,谷歌身份验证器,微软身份验证器,这种。
硬件的,银行的动态口令,早些年网易的将军令,这种。

FIDO

FIDO(Fast IDentity Online,线上快速身份验证)联盟是成立于2012年7月的行业协会。其宗旨是为解决强制认证设备的交互性和用户面临大量复杂的用户名和密码。

主要是一些巨头(Google,微软)和搞 2FA 硬件设备的厂商组件的联盟,目标是通过一个标准,让符合标准的技术能够到处适用,用起来更方便、更安全。
官方定义的愿景是 “减少世界对密码的依赖”。

协议:

  1. Universal Authentication Framework (UAF)
    UAF 1.0 Proposed Standard (December 8, 2014)
    UAF 1.1 Proposed Standard (February 2, 2017)
    UAF 1.2 Review Draft (November 28, 2017)
  2. Universal 2nd Factor (U2F)
    U2F 1.0 Proposed Standard (October 9, 2014)
    U2F 1.2 Proposed Standard (July 11, 2017)
  3. FIDO 2.0 (FIDO2, contributed to the W3C on November 12, 2015)[4]
    FIDO 2.0 Proposed Standard (September 4, 2015)
  4. Client to Authenticator Protocol (CTAP)
    CTAP 2.0 Proposed Standard (September 27, 2017)
    CTAP 2.0 Implementation Draft (February 27, 2018)

说明:

  1. FIFO 由两部分组成:通用认证框架 (UAF) 和 通用第二因素 (U2F)。
    我的理解:
  2. UAF 是一套新设计的认证方案,系统对设备进行认证,然后设备在本地通过 PIN 码,指纹等方式(主要是生物特征)对客户进行认证。
    试图取代现在简单密码比对的认证方式。
  3. U2F 是主密码 + 硬件口令,最早由 Yubico 和 Google 设计。。
  4. 现在流行的是 FIDO 联盟和 W3C 共同制定的 FIDO2,将 2FA 的相关技术拓展到 Web 领域。
    FIDO2 主要由 W3C Web 身份验证(WebAuthn)和 CTAP2 (客户端到身份验证器协议)组成。
    浏览器的 WebAuthn JS API + 客户端的 CTAP2。
    WebAuthn 向前兼容 CTAP1 / U2F。
  5. CTAP 支持 USB,蓝牙,NFC 三种方式。
  6. CTAP1(Client-to-Authenticator)约等于 U2F
  7. CTAP2,CBOR 数据格式?
  8. 主流浏览器都已支持 WebAuthn,也就是说网站可以接入了。



阿里巴巴的 IFAA
腾讯的 TUSI


今天的《科技爱好者周刊(第 219 期):如何防止帐号被黑》中说:

上周有一起安全事件。两家著名的美国互联网公司----Twillo 和 Cloudflare----被攻击了,前者还被攻破了。

手段还是钓鱼,不止钓密码,也钓了 TOTP 验证码。所以阮一峰在文章中的意思是,物理密钥会更安全。
这么说确实有道理,其实我好多次都想买一个,就是太贵,两三百。

阮一峰还提到,有部分实践(Web Authentication)在尝试采用本地设备的认证手段作为第二因子,比如手机和笔记本上的指纹识别和人脸识别。

还是希望有厂商能够推出廉价一些的 Key。

参考资料与拓展阅读

#826 winget 安装 MariaDB

2022-08-17

部署

# 安装 <https://winget.run/pkg/MariaDB/Server>
winget install mariadb.server

# 这一步应该是安装程序自动执行了
# 但是没有自动安装服务,也没有为 root 配置密码
# 有很多参数,可以参考 `mysql_install_db --help`
# mysql_install_db

# 安装服务
& 'C:\Program Files\MariaDB 10.8\bin\mysqld.exe' --install-manual MariaDB
# 根据资料,可以指定配置文件,但是我没有这么操作过,都是用的默认值:
# --defaults-file=D:\DB02\my.ini
# 如果启动另一个服务进程,记得在配置文件中指定新的 datadir

# 启动服务
# services.msc 中手动启动服务,或者,
# 管理员权限启动命令行,然后执行:
net start MariaDB
sc start MariaDB

# 停止服务
net stop MariaDB
sc stop MariaDB

# 删除服务
sc delete MariaDB
C:\>dir "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\MariaDB 10.8 (x64)"
 驱动器 C 中的卷是 Windows
 卷的序列号是 56D1-41EB

 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\MariaDB 10.8 (x64) 的目录

2022/08/15  21:33    <DIR>          .
2022/08/15  21:33    <DIR>          ..
2022/08/15  21:33             1,154 Command Prompt (MariaDB 10.8 (x64)).lnk
2022/08/15  21:33               909 Database directory (MariaDB 10.8 (x64)).lnk
2022/08/15  21:33             1,000 Error log (MariaDB 10.8 (x64)).lnk
2022/08/15  21:33               944 HeidiSQL.lnk
2022/08/15  21:33             1,000 my.ini (MariaDB 10.8 (x64)).lnk
2022/08/15  21:33             1,208 MySQL Client (MariaDB 10.8 (x64)).lnk
               6 个文件          6,215 字节
               2 个目录 309,073,027,072 可用字节

默认的 MariaDB 安装在 C:\Program Files\MariaDB 10.8,数据在 data 子目录,配置文件 my.ini 就在 data 子目录。
PS:震惊,我才发现 MariaDB 自带了一个 heidisql!!!

设置密码

这个时候可以直接通过 root 登录上去,不需要密码。
搜索 mysql.user 可以发现:

MariaDB [(none)]> select host, user, password, plugin, authentication_string from mysql.user;
+-----------+-------------+----------+-----------------------+-----------------------+
| Host      | User        | Password | plugin                | authentication_string |
+-----------+-------------+----------+-----------------------+-----------------------+
| localhost | mariadb.sys |          | mysql_native_password |                       |
| localhost | root        |          |                       |                       |
| victus    | root        |          |                       |                       |
| 127.0.0.1 | root        |          |                       |                       |
| ::1       | root        |          |                       |                       |
+-----------+-------------+----------+-----------------------+-----------------------+
5 rows in set (0.001 sec)
mariadb-admin status -uroot
mysql -uroot

# 设置密码
# 如果忘记密码登录不进去了,怎么重置,这是另一个话题了
& 'C:\Program Files\MariaDB 10.8\bin\mysqladmin.exe' -uroot password 123456

默认配置

SHOW VARIABLES LIKE "%char%";
Variable_name Value
character_set_client utf8mb4
character_set_connection utf8mb4
character_set_database latin1
character_set_filesystem binary
character_set_results utf8mb4
character_set_server latin1
character_set_system utf8mb3
character_sets_dir C:\Program Files\MariaDB 10.8\share\charsets\
SHOW VARIABLES LIKE "%system%";
SHOW VARIABLES LIKE "%log%";
SHOW VARIABLES LIKE "%version%";
SHOW VARIABLES LIKE "%dir%";

SHOW CHARACTER SET;
SHOW COLLATION;

#825 Chrome/Edge 批量删除历史记录

2022-08-14
  1. 根据域名等关键字搜索出来相关记录
    在历史记录上点击右键菜单中的 来自相同站点的更多内容 也行,其实就是按域名搜索
  2. 选中第一个,然后滚动到最下面,按住 Shift,选中最后一个
  3. 点击右上角的 删除 按钮

#824 Win11 右键菜单

2022-08-13

Windows 11 右键菜单样式调整了,像是变成两级了,我经常需要点击 “显示更多选项”(Show more options),感觉很麻烦,今天在网上找到了解决办法:

# enable
reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve​

# disable
reg delete "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" /f​

# restart explorer
taskkill /f /im explorer.exe
start explorer.exe

#823 PuTTY 注册表导出

2022-08-07
  1. Win + R, regedit 打开注册表编辑器。
  2. 逐级进入 HKEY_CURRENT_USER\Software\SimonTatham\PuTTY 目录
  3. 导出这个目录到 puttySettings.reg 文件
  4. 导出下一级目录 Sessions 为 puttySessions.reg 文件

regExport.bat

reg export HKEY_CURRENT_USER\Software\SimonTatham\PuTTY "%USERPROFILE%\Desktop\puttySettings.reg"
reg export HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions "%USERPROFILE%\Desktop\puttySessions.reg"

或者:

regedit /e "%USERPROFILE%\Desktop\puttySettings.reg" HKEY_CURRENT_USER\Software\SimonTatham\PuTTY
regedit /e "%USERPROFILE%\Desktop\puttySessions.reg" HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions

#822 Viper: Go 项目配置管理

2022-07-22
  • main.go
package main

import (
    "fmt"
    "os"

    "github.com/spf13/pflag"
    "github.com/spf13/viper"
)

func main() {
    // 1. 设置 Viper 配置
    viper.SetConfigName("config") // 配置文件名(不带后缀)
    viper.AddConfigPath(".")      // 配置文件路径
    viper.SetConfigType("yaml")   // 配置文件类型
    viper.AutomaticEnv()          // 自动读取环境变量

    // 2. 设置命令行参数
    pflag.String("name", "", "project name")
    pflag.String("host", "", "host address")
    pflag.String("port", "", "port number")
    pflag.String("config", "./config.yaml", "config file") // 配置文件参数
    pflag.Parse()
    viper.BindPFlags(pflag.CommandLine) // 将命令行参数绑定到 Viper

    // 3. 读取配置文件
    if configFile := viper.GetString("config"); configFile != "" {
        fmt.Println(configFile)
        if err := viper.ReadInConfig(); err != nil {
            fmt.Fprintf(os.Stderr, "读取配置文件失败:%v\n", err)
            os.Exit(1)
        }
    }

    // 4. 读取配置项
    projectName := viper.GetString("name")
    port := viper.GetInt("port")
    fmt.Printf("ProjectName: %s, Port: %d\n", projectName, port)
}
  • config.yaml
name: hello
host: 10.10.0.172
port: 9090
  • 支持环境变量、命令行参数、配置文件。
  • 支持多种配置文件,包括 JSON,YAML,TOML,INI 等。
  • 支持监控配置文件的变化,会自动加载新的配置。
  • 支持从远程加载配置,比如 etcd、zk、consul、redis 等,
    也可以通过 RemoteProvider 接口自定义远程数据源:
type RemoteProvider interface {
    Set(key string, value []byte) error
    Watch(key string) (chan *RemoteResponse, chan error)
    Get(key string) ([]byte, error)
}
  • 支持默认值。

#821 好用的 golang 库:hashring(一致性哈希)

2022-07-20

通过对 key 做哈希,来实现 Redis 服务器的分片。
用这个例子来演示这个小库的用法:

package main

import (
    "crypto/rand"
    "encoding/base64"
    "fmt"
    "log"
    "time"

    "github.com/go-redis/redis"
    "github.com/serialx/hashring"
)

func RandomString(length int) (string, error) {
    b := make([]byte, length)
    _, err := rand.Read(b)
    if err != nil {
        return "", err
    }
    return base64.URLEncoding.EncodeToString(b)[:length], nil
}

func main() {
    redisServers := map[string]int{
        "redis1:6379": 200,
        "redis2:6379": 100,
    }

    redisClients := []*redis.Client{}
    for uri, _ := range redisServers {
        redisClients = append(redisClients, redis.NewClient(&redis.Options{Addr: uri}))
    }

    log.Println(redisServers)
    ring := hashring.NewWithWeights(redisServers)

    stat := map[string]int{}
    for uri, _ := range redisServers {
        stat[uri] = 0
    }

    for i := 0; i < 100; i++ {
        randstr, _ := RandomString(8)
        key := "test:randkey:" + randstr
        node, ok := ring.GetNode(key)
        if !ok {
            log.Panicf("cannot assign a redis client by key: %#v", key)
        }
        log.Printf("%s -> %s", key, node)
        stat[node]++

        var client *redis.Client
        for _, _client := range redisClients {
            if node == _client.Options().Addr {
                client = _client
                break
            }
        }
        if client == nil {
            log.Panicf("redis client assigned error: %#v", node)
        }

        client.Set(key, 1, time.Minute)
    }

    fmt.Println(stat)
}