Warp 终端初体验

Warp 是一个 Rust 编写,使用 GPU 渲染的终端(terminal)应用。目标是提升开发者的效率。

最近 Warp 发布了新闻稿,筹集了 2300 万美元的资金全力用来构建这个终端。

它之前筹集了 600 万美元的种子轮融资,由 GV 领投,Neo 和 BoxGroup 参投。还筹集了 1700 万美元的 A 轮融资,由 Figma 的联合创始人兼首席执行官 Dylan Field 领投。由企业家主导的这一轮投资,其参与者包括 Elad Gil、LinkedIn 前首席执行官 Jeff Weiner 和 Salesforce 的联合创始人兼联合首席执行官 Marc Benioff。

Warp 想要解决的问题

简化配置

上手体验的过程也可以知道,Warp 基本上没什么配置,基本上所有的功能都是内建快捷键调用,对新手非常友好。

速度

早在之前的文章中我就 提到过 因为使用越来越多的 zsh 插件,导致每一次打开新的 Tab 终端都要有一个明显的停顿,虽然后来使用 zinit 优化了一下插件加载,但是还是会感觉到一小点的卡顿,希望 Warp 能解决这个问题吧。

通过终端自身的能力,可以精减掉一些 zsh 的插件。

更加智能

Warp 的创始人 Zach Lloyd 说过,走过任何一个开发人员的桌面,都会看到一个打开的终端,还有代码编辑器,VS Code 完成了代码编辑器的重新定义,Warp 就去重新定义终端。

Warp 内置的命令自动补全,还有尚且不是很完善的 AI 搜索都是朝着智能化的方向前进的。GitHub Copilot 已经让我非常惊讶其代码自动补全的能力,我相信 Warp 未来在 AI 自动补全方面也会令人耳目一新。

以终端作为入口,

协作

Warp 的创始人在总结其过去 20 年的程序生涯的时候说过现存的终端存在的两个痛点:

  • 难用
  • 只能一个人用

想来和他自身作为 Google Docs 的开发有着非常大的关系。当前的任何桌面程序如果加上了多人协作都是一个非常大的想象空间。那为什么终端不行?

在 Warp 中用户可以共享自己的命令行,设置,和历史。

上手体验

可以点击 这里 下载体验。

登录不上问题

如果在国内,大概率会卡在登录的界面(在还没有开放 beta testing 的时候会卡在输入邀请码的界面)。

这个时候需要本地其一个 1080 端口的代理,然后使用代理来启动 Warp:

export HTTP_PROXY=http://127.0.0.1:1080
export HTTPS_PROXY=http://127.0.0.1:1080

/Applications/Warp.app/Contents/MacOS/stable

在 macOS 上推荐使用 Clash for windows

几个重要的快捷键

  • ctrl + shift + r 可以从社区或者自定义的命令中搜索并执行长命令
  • cmd + p 非常常见的 Command Palette,现在很多应用都使用这个涉及,我现在在用的 Obsidian 也是,可以调用出应用内置的命令
  • ctrl + r 搜索历史
  • cmd + d 切分窗口
  • ctrl + cmd + t 用来切换主题!

更多的快捷键可以在设置中查看。

自动补全

Warp 自带了命令的补全,效果还不错。

warp auto suggestions

Warp 提供了对于命令结果的快速复制,以及分享,点击 Share 可以非常轻松的把命令结果分享给别人。

warp command copy

比如对于我上面的 git --help 的结果可以到 这里查看

当然如果没有 Warp,我会在 Tmux 中用 Tmux 的复制粘贴来实现这个需要。

存在的问题

  • 一个终端竟然需要登录!当然我能理解这样的一个商业模式,毕竟这款终端可能未来会商业化,向用户收费,但如果要让我付费,可能我会去看看其带给我的体验是不是要好过目前的方案。并且前期在测试阶段为了不扩大 bug 可能产生的负面影响,所以在有限人群内测试都是可以理解的。
  • Warp 破坏掉了我之前的 fzf 的一些操作,比如我之前设定 fe 就是 fuzzy find 当前目录,然后输入模糊搜索词,回车之后就会立即用 vim 编辑,但是在 Warp 中并不能用 fzf。

当然这可能和 fe 使用的 zsh 脚本有关系,有时间再看看怎么解决。

which fe
fe () {
    local files
    IFS=$'\n' files=($(fzf-tmux --query="$1" --multi --select-1 --exit-0))
    [[ -n "$files" ]] && ${EDITOR:-vim} "${files[@]}"
}

总结

Warp 不需要用户查看文档也可以有一个不错的上手体验,更不像其他终端那样需要一个非常复杂的配置文档才能将其调教得比较好用。

如果你看完这篇文章觉得 Warp.dev 还不错,可以点击 邀请 来尝试一下。

相关联终端

  • 在 macOS 上我一直都用的 kitty 这样一款终端,通过简单的配置,日常用起来目前还没有遇到比较大的问题,配合 zsh, tmux 还算得上顺手
  • [[Mac 应用 iTerm2]] 是一款比较正统的终端
  • [[Mac 应用 alacritty 终端]] 也是一款 GPU 加速终端
  • [[hyper.is]] 一款基于 Electron 的终端
  • [[wezterm-terminal]] 是另一款 GPU 加速的终端,用 Rust 和 Lua 编写的,轻度体验了一下确实比较快,但是最近还没来得及深度体验。
  • fig.io 是一款可以嵌入到其他 IDE 内部使用的终端,也实现了命令的自动补全等等功能。

reference


2022-03-23 terminal , macos , warp , rust , gpu , command , iterm , tmux , vim , zsh

Ubuntu 上命令行设置时区

一台新的 Ubuntu 服务器通常时区可能不是想要的时区,可以通过如下步骤设定时区。

检查当前时区,在命令行下输入 date:

date

可以查看当前的时间。

输入 timedatectl 可以查看更具体的时区。

使用 timedatectl

修改为东八区北京时间。

sudo timedatectl set-timezone "Asia/Shanghai"

ln

也可以通过软链接来修改系统的时区,在 Linux 下 /etc/localtime 中定义了系统要使用的时区。正确的配置在 /usr/share/zonefine 目录中

mv /etc/localtime /etc/localtime-backup
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

修改完成后可以通过 timedatectl 来验证。


2022-03-22 ubuntu , server , timezone

什么是 DMARC

DMARC 是 Domain-based Message Authentication Reporting & Conformance 的缩写,是一个标准的电子邮件验证标准。1 DMARC 帮助邮箱管理员防止黑客或其他攻击者伪装(Spoofing)其组织和域名。Spoofing(伪装)是一种电子邮件攻击方式,攻击者通过伪装邮件地址中的 From 字段,来假装发件人。DMARC 会检查电子邮件是否来自邮件中声称的发送者。

DMARC 构建在 [[SPF]] 和 [[DKIM]] 基础之上,来防止域名欺诈。

之前提到过自建域名邮箱 的文章中就配置过 DMARC,这篇文章就对 DMARC 具体展开讲讲。

DMARC 是什么?

DMARC 建立在广泛使用的 SPF 和 DKIM 协议上, 并且添加了域名对齐检查和报告发送功能。这样可以有效保护域名免受钓鱼攻击。

来自 dmarc.org 的示意图:

为什么 DMARC 如此重要?

根据 dmarc.org 的说法:

随着社交网络和电子商务的繁荣,垃圾邮件发送者和钓鱼攻击发起者基于利益的原因,想要入侵用户的账户,破解用户的信用卡等。Email 的相对容易攻击的特性备受罪犯们的青睐。只是简单地把企业的 logo 嵌入到 email 中,就能获取用户的信任。

用户很难辨别一封假的 email,邮件提供商也很难判断哪些邮件有可能会伤害用户。邮件发送者基本上对邮件认证的问题一无所知,因为他们缺少合理的反馈机制。那些尝试部署 SPF 和 DKIM 的企业的进展非常慢,因为没有监督进度和除错的机制。

DMARC 解决了这些问题。它帮助 email 发送者和接收者来共同保护 email,避免了昂贵的入侵损失。

DMARC 记录是什么?

DMARC 记录作为 TXT 记录发布到 DNS 中。指示邮件收件服务当验证失败时,应当如何处理收到的邮件。

比如以下发布在域名 “sender.exampledomain.com” 上的 DMARC 记录:

v=DMARC1;p=reject;pct=100;rua=mailto:postmaster@exampledomain.com

在这个例子中表示发件人要求收件人如果遇到验证未通过的邮件,则完全拒绝,并且发送相关报告到 postmaster@exampledomain.com。如果发件人在测试配置,”reject” 可以被替换成 “quarantine”,表示验证未通过的 邮件将被隔离。

DMARC 记录标签

DMARC 记录使用可扩展的 “标签-值” 语法。

这是一个典型的 DMARC 记录:

v=DMARC1; p=reject; rua=mailto: dmarc_report@example.com; ruf=mailto: dmarc_report@example.com; pct=100; adkim=s; aspf=s;

它由多个key-value标签组成。这些标签会告诉邮件服务提供商如何发送 DMARC 报告:

  • v 是 DMARC 协议版本,它的值必须是 DMARC1
  • p 是策略,策略将被应用到验证失败的邮件上,可以设置成 ‘none’, ‘quarantine’, 或者 ‘reject’
    • ‘none’ 如果接收服务器接收到的邮件没有通过 DMARC 校验,不会做任何操作,邮件会正常被递交
    • ‘quarantine’ 用来隔离可疑邮件,如果接收服务器收到的邮件没有通过验证,那么会把邮件单独隔离
    • ‘reject’ 告诉接收方拒收可疑邮件
  • rua 是一组用来接收报告的电子邮件地址(DMARC aggregate)
  • ruf 是一系列用来接受失败报告的电邮地址(DMARC failure)
  • pct 对失败邮件应用策略的百分比
  • adkim 制定 DKIM 的对齐策略,可选 sr
  • aspf 制定 SPF 的对齐策略,可选 sr

DMARC 策略

DMARC 策略是在 DMARC 记录中制定的 p 标签。它指示邮件服务提供商应该如何处理验证失败的邮件。

DMARC 策略可以取三个值中的一个:none (monitor), quarantine 和 reject。

– none: 邮件提供商对验证失败邮件不采取任何处理。这个模式用来收集 DMARC 报告。 – quarantine: 邮件提供商把验证失败邮件放到垃圾邮件文件夹。 – reject: 邮件提供商拒收验证失败邮件。

DMARC alignment options

DMARC 对齐策略。DMARC 通过检验 header 部分是否和发送的域名相匹配,这个动作称为 alignment,这个部分验证依赖 SPF 和 DKIM。

用户可以在 DMARC 中配置两种 alignment 模式,strictrelaxed。上面提到的 aspfadkim 选项就是这个作用。sr 分别是两个缩写。

验证方式 Strict Relaxed
SPF SPF 验证域名,和邮件 Header 中 From 一致 Header 中的 From 必须匹配域名或子域名
DKIM From 中的地址和 DKIM 配置一致 From 必须匹配 DKIM signature d= 后配置的域名或子域名

Envelope sender address: 是 Return-Path 头的邮件地址,收件人是看不到该地址的

From: 地址,收件人看到的地址

SPF alignment example

Envelop sender address Header From strict relaxed
admin@example.com admin@example.com Pass Pass
admin@mail.example.com admin@example.com Fail Pass
admin@example.com admin@example.org Fail Fail

DKIM alignment example

DKIM signature domain 中的 d= 后面部分。

From DKIM d= strict relaxed
admin@example.com example.com Pass Pass
admin@mail.example.com example.com Fail Pass
admin@example.org example.com Fail Fail

发布 DMARC 记录

发布 DMARC 记录需要你有权限修改域名的 DNS 记录。

在 DNS 记录后台,需要创建一条 DMARC 记录。

创建一条 TXT 记录:

Type: TXT Host: _dmarc TXT Value: (DMARC record generated above) TTL: 1 hour

以 Cloudflare 后台为例:

cloudflare dmarc

如果用其他的域名服务的话,界面类似。

保存更改。现在你已经在域名 yourdomain.com 上面成功发布 DMARC 记录了。

reference


2022-03-20 dmarc , email , domain , spf , dkim

Go 语言学习笔记 4:Go 语言的控制语句

常见的语句:

  • condition,条件
  • for-loop,循环
  • goto,跳转(特殊)

statement vs expression

下文中使用 statement 和 expression 来表达一些语句的区别:

  • statement, 通常用来指代一个操作,可以是赋值操作,等等
  • expression 通常用来指代一个值,这个值可以是一个语句的返回,也可以是一个函数的返回

条件语句

通用:

if InitSimpleStatement; Condition {
    // do something
} else {
    // other
}
  • 和其他语言一样 else 是可选的
  • InitSimpleStatement 是可选的,必须是 Simple Statement,通常这部分是一个简单变量的定义或者赋值
  • Condition 必须是一个返回值是 boolean 值的 expression,这部分可以添加 () 或者不加。
  • 如果没有 InitSimpleStatement,那么后面的 ; 也是可选的

举例:

if a < 4 {
    return 0
} else {
    return 1
}

更复杂一些的:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UnixNano())

    if n := rand.Int(); n%2 == 0 {
        fmt.Println(n, "is an even number.")
    } else {
        fmt.Println(n, "is an odd number.")
    }

    n := rand.Int() % 2 // this n is not the above n.
    if n % 2 == 0 {
        fmt.Println("An even number.")
    }

    if ; n % 2 != 0 {
        fmt.Println("An odd number.")
    }
}

switch-case

一种特殊的条件分支语句。

switch i {  
case 0:  
   fmt.Printf("0")  
case 1:  
   fmt.Printf("1")  
case 2:  
   fmt.Printf("2")  
case 3:  
   fallthrough  
case 4, 5, 6:  
   fmt.Printf("4,5,6")  
default:  
   fmt.Printf("Default")  
}

for loop

for 循环的格式:

for InitSimpleStatement; Condition; PostSimpleStatement {
    // do something
}
  • for 循环的语法和其他语言相差不多,但不需要 ()
for i := 0; i < 10; i++ {
    fmt.Println(i)
}

几个变种:

var i = 0
for ; i < 10; {
    fmt.Println(i)
    i++
}
for i < 20 {
    // do something
    i++
}
for i := 0; ; i++ {
    if i >= 10 {
        break
    }
}

使用 for range 遍历 map:

for key, value := range oldMap {
    newMap[key] = value
}

goto 跳转语句和 Label 定义

Java 语言不支持 goto 关键字,但是 goto 是作为关键字保留了下来,但是 Java 中可以使用 label 关键字来达到 goto 的效果。

Go 语言支持 goto statement,goto 关键字必须跟一个 label 来表达跳转到的地方。

package main

import "fmt"

func main() {
    i := 0
Here: // declare a label
    fmt.Println(i)
    i++
    if i < 10 {
        goto Here // goto label
    }
}

需要注意的是 label 对于最里层的代码块是不可见的。

breakcontinue 关键字后面都可以接 label

defer 关键字

defer 关键字会推迟方法的执行,知道外层的方法返回之后再执行。

defer 的调用的参数会立即

A defer statement defers the execution of a function until the surrounding function returns.

The deferred call’s arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.

package main

import "fmt"

func main() {
    defer fmt.Println("world")

    fmt.Println("hello")
}

reference


2022-03-09 golang , programming , control-flow

macOS 下启动器 Raycast 简单使用

在逛 Twitter 的时候看到有人分享了一款 Launcher,叫做 Raycast,因为平时一直使用 [[Alfred]] 倒是没有引起我的太多注意,但今天又看到了一次,所以就想好好来了解一下这个新出来的启动器。

在 macOS 上其实有非常多的启动器,包括了系统默认的 [[Spotlight]],以及很多第三方应用,包括了 [[Alfred]], [[LaunchBar]] 在内的无数优质应用。这些应用有着各自的特点。但最重要的一点就是提高我们打开应用的速度,以及在各个小细节方面提高易用程度,比如我最喜欢的 Alfred 的一个贴心功能就是历史粘贴板,在 Linux 上我一直都是用的 [[fcitx]] 默认的快捷键 Ctrl+;,所以在 macOS 也用一样的快捷键。

安装

安装:

brew install --cask raycast

特性

  • 最基本的功能,启动 macOS 上的应用,搜索文件
  • 历史粘贴板
  • 搜索打开书签
  • 集成第三方应用
    • 在 GitHub,Jira 等等中创建、搜索、关闭 issues
    • 批准、合并和关闭 GitHub Pull Request
    • 调用 Zoom 会议
  • 支持快捷键设置日程、待办事项
  • 支持扩展脚本

使用

Snippet

写过代码的人应该对 Snippet 非常熟悉,我们可以定义一些常用的代码块,然后通过简单的几个字母来快速补充一段内容。

在 Raycast 中,可以通过输入 Create snippet 来创建 Snippet,在弹出的设置窗口中输入想要设置的内容。

raycast-snippet-create

注意下面的 Keyword, 输入 Keyword 的内容就是唤起整个 Snippet 的快捷键。

比如当我输入 :blog 的时候就会自动补全成https://blog.einverne.info

如果有读者记得的话,我在不就之前介绍过一款跨平台的 Text Expander —- Espanso,也能够做到相同的事情。有兴趣可以查看espanso:Rust 编写的跨平台开源文本扩展工具

Clipboard History

在 Raycast 中输入 Clipboard History 可以打开粘贴板历史。

这里值得注意的是 Raycast 所有数据都是本地加密存储,所以可以不用担心粘贴板的隐私问题。

同样,在应用设置中,可以设置快捷键,我就设置成和 Linux 下一致的 Ctrl+;

raycast clipboard history hotkey

Search Screenshot

Raycast 支持直接搜索图片中的内容,还可以选中图片之后使用,cmd + Shift + a 使用 Cleanshot 对图片标注。

Store

输入 Store 可以打开 Raycast 的商店,然后可以在其中安装、启用非常多的三方插件。

目前Raycast已经接入了 GitHub、Jira、G Suite、Linear、Asana、zoom,Notion,Things,Raindrop,Todolist 等服务,能够快速完成特定操作。

Browser Bookmarks

首先在 Store 中安装 Browser Bookmarks

raycast-store-install-bookmarks

然后在设置中启用 Chrome:

raycast browser bookmarks

注意选择正确的 Profile。

然后就可以在 Raycast 中输入 Browser Bookmark 来搜索 Chrome 的书签了。

browser-bookmarks-search

不过需要注意的是,只有书签存在中文、英文才能被搜索出来,如果书签没有描述,或者你忘记了域名,那么也是无可奈何的。

悬浮标签 Floating Notes

在 Raycast 中输入 Floating Notes 之后就会在桌面最顶层开启一个悬浮便签,便签可以移动位置,但是永远在所有窗口的最上面。非常方便用来记录快速的想法,待办事项等等。

raycast-floating-notes

在输入 Float 之后,有两个选项:

  • Toggle Floating Notes Focus,这个选项会将光标移动到便签中
  • Toggle Floating Notes Windows 会显示隐藏便签窗口

日程管理和待办事项

Raycast 可以直接连接 Calendar,因为我的 macOS 上的日历同步了 Google Calendar 的数据,所以可以直接看到我的日程。

在 Raycast 中输入 My Schedule 即可。第一次可能需要授权。

同样可以输入 reminder 来查看待办事项,或者根据提示来创建待办事项。

系统设置

比如输入 volume 可以调整音量。

其他比如计算器、汇率转换、时间查询等等基础功能就不再展开。

如果有时间会再讲讲如何在 Raycast 中执行自定义脚本,或者如何编写自己的扩展。 Raycast 支持的脚本语言,Bash、Swift、AppleScript。


2022-03-01 launcher , alfred , macos , mac-application

电子邮件是如何工作的

之前听一个播客,里面提到基于协议的应用不会轻易的被历史淘汰,想想基于 HTTP 协议的 Web 浏览器,基于 SMTP 的电子邮件,在过去的几十年里,存在于 HTTP 上层的网站更新换代了很多遍,但底层的协议依然还是 HTTP,而倒闭的电子邮箱也不在少数。但如今互联网依然还依赖 HTTP 协议,电子邮箱虽然没有那么流行但也是基础服务之一。

过去很多年里面,我陆陆续续一直在寻找一个完美代替 Gmail 的存在,我的代办事项中一直存在一条叫做如何自建邮箱服务的 TODO,我陆陆续续体验过很多新出现的加密邮箱服务,但也还是一直用着 Gmail。陆陆续续把很多数据从 Google 的服务中迁移出来,但唯独摆脱不了 Gmail。但是最近体验了一些自建的邮箱服务之后,感觉自己可以现在再来尝试一下自建邮件服务器了。

过去我曾经体验过的自建邮箱服务器:

  • [[Poste]] 一个单一 Docker 镜像的邮件服务器,存在免费版本和收费版本
  • [[Mailu]],一个 Python 编写的邮件服务器,可以使用 Docker 部署
  • [[mailcow]],同样是一个可以使用 Docker 部署的邮件服务器
  • [[Mail-in-a-Box]],一个非常方便部署的邮箱服务器
  • [[postal]],一个使用 Rust 实现的邮件服务器
  • [[Maddy]] 一个使用 Go 语言实现的邮件服务器,没有 Webmail
  • [[Salmon]] Python 实现的邮件服务器

还有一些比如 [[iRedMail]]、[[modoboa]]、[[zimbra]] 等等的服务还没有仔细看,但都能实现邮件服务器。

在尝试的过程中觉得自己还需要补习一些基本的知识,因为在自建邮箱服务的时候不可避免的需要配置多个 DNS 记录,包括了 [[MX 记录]],[[SPF]],[[DMARC]] 等等。如果理解了邮件的发送过程,会对这些有更多的理解。所以下面就再学习记录一下邮件发送过程。

邮件服务器发送与接受邮件

假设用户 a@gmail.com 发送一封邮件到 b@qq.com,会执行如下的流程。

Webmail

为了简化理解,下面的所有操作都是通过网页版的 Web 应用触发。

当我们在 Gmail 网页上撰写一封邮件,并点击发送按钮之后。Gmail 会用自己的内部协议链接 Gmail 的 Outgoing SMTP 邮件服务器。

Outgoing SMTP 验证用户权限,然后将邮件以 MIME 格式发送到发送队列中。

查询 MX 记录

Gmail SMTP 服务器会通过 DNS 查询到 qq.com MX 记录,找到服务器 IP 所在。

在 Linux 下也可以通过 dig mx qq.com 来查询到。这一步在对应到自建的邮件服务器的时候,就是通过配置 DNS 的 MX 记录来实现的。

一般情况下会配置一个 A 记录 mx.example.com 指向服务器的 IP 地址。然后再配置一个 MX 记录,@ 全部域名的 MX 请求全部转发给 mx.example.com

MX 这里指的是 Mail Exchanger。

SMTP 发送

当 Gmail 的服务器找到 QQ 邮箱的 IP 地址之后,邮件就会通过 SMTP 协议连接服务器的连接,尝试发送给 QQ 的服务器。

为了简化理解,SMTP 传输的时候就直接声明,我 a@gmail.com ,我要发送邮件到 b@qq.com ,内容是某某某。

这中间会发现不存在任何验证发送方身份的过程,这也就意味着任何人都可以伪装一个任意的发送邮箱以一个伪装的邮箱发送邮件。SMTP 最早是建立在信任的基础之上的,但是也给后面使用留下了一些漏洞,为了修复这个漏洞发明了 [[SPF]]。具体见下文。

接收

QQ 邮箱的服务器接收到 Gmail 的邮件之后再决定发给具体谁的邮箱。

SMTP

[[SMTP]] 是 Simple Mail Transfer Protocol 的缩写,从协议名称上也能看出来是一个邮件传输协议。

SPF

上文提到过 SMTP 协议发送邮件的过程中没有验证发送方,这也就意味着发信方可以任意指定发件人邮箱地址,这会存在一些安全问题。

具体来说,本来我的 Gmail 邮箱是 a@gmail.com,假如有不法分子,就可以利用这个漏洞,伪装成自己是 a@gmail.com 给别人发送邮件。

SPF 的目的就是为了防止伪造发信人。

SPF 的原理

SPF 的实现原理非常简单,就是通过添加一条 DNS 记录。

如果邮件服务器收到一封来自主机 1.1.1.1 的邮件,并且发件人是 a@gmai.com,为了确认发件人,邮件服务器就会去查询 gmail.com 的 SPF 记录。如果域名设置了 SPF 记录,允许 1.1.1.1 的 IP 地址发送邮件,那么收件的邮件服务器就会认为邮件是合法的,否则就会退信。

有了 SPF 记录之后,如果有人想要伪装成 a@gmail.com 他既不能修改 gmail.com 的 DNS 解析,也无法伪造 IP 地址,就有效的防止了伪装。

SPF 的语法

在自建邮件服务器的时候,经常会让我们设置一个 TXT 记录,配置值为 v=spf1 mx ~all,这表示的意思是允许当前域名的 MX 记录对应的 IP 地址。

下面再举个非常常见的例子:

v=spf1 a mx ip4:173.10.10.10 -all

表示允许当前域名配置的 A 记录,MX 记录的 IP 地址,以及一个额外的 IP。

SPF 存在的问题

通过上面的描述我们知道通过 SPF 机制可以有效地规避了发送邮件方伪造发件人的问题。但实际使用的时候,如果你使用多个邮箱,然后设置了其中 c@163.com 邮箱自动转发到 a@gmail.com 中。

那么这个时候如果 b@qq.com QQ 邮箱发送了一封邮件到 c@163.com 邮箱,163 邮箱原封不动地将邮件转发到 Gmail 邮箱,这个时候发件人是 b@qq.com,但是 Gmail 回去查询 qq.com 的 SPF 记录,但会发现并不包含 163 邮箱的 IP 地址,会误判转发的邮件。

所以又诞生了 DKIM

DKIM

[[DKIM]] 是 DomainKeys Identified Mail 的缩写,允许发送者通过在邮件的 header 中包含一段数字签名来验证邮件。DKIM 使用公私密钥来确保邮件内容是从授信的邮件服务器发送的。

还是利用上面的例子,因为我们把所有发送到 163 邮箱的邮件都转发到了 Gmail 邮箱,所以来自 QQ 邮箱的邮件在验证 SPF 时会失败。

那么在 DKIM 中,发送邮件的服务器,比如 QQ 邮箱,会使用公私钥对邮件内容进行签名,并将签名和邮件内容一起发送。当 Gmail 收到从 163 邮箱转发过来的 QQ 邮箱邮件的时候,就会去查询 qq.com 的 DNS 记录,拿到公钥。然后使用公钥和签名来验证邮件内容。如果验签不通过,则将邮件判定为伪造。

这里就需要我们再配置一个 DKIM 的 DNS 记录。TXT,键值是页面中的内容。

在 Mailu 的后台可以看到 DKIM 的设置

mailu dkim

DMARC

经过了 SPF 和 DKIM 的保证是不是就可以完美的发送接收邮件了,其实并不能,我们通过邮件后台来看一下邮件的原始文本。

MIME-Version: 1.0
Return-Path: xxx@fake.com
DKIM-Signature: d=fake.com,b=adceabkekd12
Date: Tue, 22 Mar 2022 06:37:58 +0000
Content-Type: multipart/alternative;
 boundary="--=_RainLoop_587_997816661.1647931078"
From: admin@a.com
Message-ID: <a67d96a38592cdad46cca89e98dda26d@techfm.club>
Subject: Seems it works
To: "Somebody" <a@gmail.com>


----=_RainLoop_587_997816661.1647931078
Content-Type: text/plain; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

~~

----=_RainLoop_587_997816661.1647931078
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html><html><head><meta http-equiv=3D"Content-Type" content=3D"t=
ext/html; charset=3Dutf-8" /></head><body><div data-html-editor-font-wrap=
per=3D"true" style=3D"font-family: arial, sans-serif; font-size: 13px;"><=
br>~~<signature></signature></div></body></html>

----=_RainLoop_587_997816661.1647931078--

SPF 解决了接收方验证发件人域名 SPF 记录内 IP 地址从而验证发件人的问题。但是因为 SPF 定义的发件人是 RFC5321 协议中规定的 Return-Path,而 DKIM 在邮件头中直接包含了域名,只要使用该域名的公钥验证通过即可。

而现在的邮件服务给用户展示的发件人都是 From 字段,而不是 SPF 的 Return-Path,也不是 DKIM 的 DKIM-Sginatur: d=,所以攻击者可以通过伪造这两个字段,发送如上的邮件,完美通过 SPF 和 DKIM 检查,因为 SPF 检查 Return-Path 而 DKIM 验证的 d= 也是 fake.com 所以最终用户看到的发件人却是 admin@q.com

所以就诞生了 [[DMARC]]。DMARC 结合了 SPF 和 DKIM,规定了 Return-PathDKIM-Signature: d= 两个至少需要有一个与 From 头对应,否则判定为失败。

当邮件服务器接收到邮件时,先验证 DKIM,SPF,然后再根据 DMARC 的配置,检查。这样就能确保最终用户看到的 From 字段和 SPF、DKIM 认证的发件人一致了。

reference


2022-03-01 email , mail , self-hosted , mail-server , gmail , smtp , linux , pop , imap , dns , spf

腾讯轻量云服务器挂载云硬盘

之前看到轻量云服务器做活动,500 GB 的存储空间一年只需要 9.9 元,配合之前的轻量服务器正好买了 3 年。

挂载到之前的轻量云服务器作为数据盘。

  • 限国内轻量云服务器
  • 仅有100GB、500GB、1TB,分别售价一年为 5 元,9.9 元,和 19.9 元,可以一年或者三年购买。
  • 选择区域时需要与轻量云服务器位置一致

tencent cloud drive discount

如果感兴趣可以 Follow 我的 Twitter,之后有更多的优惠会及时发出来。

我本人的轻量云并没有那么多的流量,所以放弃了 1T 的空间选择了折中的 500G。

初始化云硬盘

sudo fdisk -l
# 创建文件系统
sudo mkfs -t ext4 /dev/vdb
# 新建挂载点
sudo mkdir /mnt
# 挂载
sudo mount /dev/vdb
sudo df -TH

Linux 系统开机自动挂载磁盘

sudo blkid /dev/vdb
/dev/vdb: UUID="8cxxxxxx-9a49-49bf-8185-xxxxxxxxxxxx" TYPE="ext4"

修改 /etc/fstab 文件

《设备信息》 《挂载点》 《文件系统格式》 《文件系统安装选项》 《文件系统转储频率》 《启动时的文件系统检查顺序》
UUID=d489ca1c-5057-4536-81cb-ceb2847f9954 /mnt ext4 defaults 0 0

最后执行:

sudo mount -a

可以用 df -h 来验证。

reference


2022-02-26 tencent , cloud , vps , cloud-drive , mount , linux

使用 Beancount 记账篇三:周期账单

在 Beancount 使用的过程中难免会出现周期性重复的账单,比如房租,水电,网费,以及可能的分期付款账单,每个月的订阅费用等等。在之前我都是在 Vim 下复制粘贴然后改改,倒是没有那么麻烦,比如房租,基本上几秒钟就能搞定,但是长期下来我发现这样一来比较繁琐,因为我基本上每个月只对账一次,也不会一直开着 fava,所以有可能有遗漏,排查起来麻烦,二来为了管理方便我需要单独设立一个文件来管理,比如房租会单独有一个 rent.bean 文件,所以最后并没有向日常的账单那样是按照月份来管理的,如果要从时间上来统一管理就比较麻烦。

不过随手一查文档,发现 Beancount 提供了一个插件 plugin "beancount.plugins.forecast 专门用来处理周期性账单(交易),可以按照每月费用的自动生成。并且只需要记录一次,之后可以按照设定的周期截止时间,或者执行几次来自动完成对账。体验了一下感觉非常不错,下面就记录一下使用过程。

首先在 main.bean 中引入插件:

plugin "beancount.plugins.forecast"

然后就可以在 *.bean 文件中定义分期语法。

这里举一个例子,比如每个月3000的房租:

plugin "beancount.plugins.forecast"

2021-01-01 open Expenses:House:Rent
2021-01-01 open Assets:DebitCard:CMB

2021-05-17 # "House Rent [MONTHLY]"
    Expenses:House:Rent   3000 CNY
    Assets:DebitCard:CMB

使用上了上述的交易之后,Beancount 会每个月自动记录一笔,在 Fava 中查看的时候会默认把今年剩余的月份都补全。注意上面的语法中 # 是必须的,并且 [MONTHLY] 定义了记账周期。

同样的,这里的 MONTHLY 可以替换成

  • YEARLY,每年
  • WEEKLY,每周
  • DAILY,每天

更进一步,如果已知了账单的循环次数,比如分期付款的时候分了 12 期,那么可以在 MONTHLY 后面使用如下的语法:

2022-02-08 # "Computer [MONTHLY REPEAT 12 TIMES]"
  Expenses:DigitalDevice                      20000 USD
  Liabilities:CreditCard:CMB

其中的 [MONTHLY REPEAT 12 TIMES] 就定义了循环的次数。

另外一种情况就是不清楚次数,但是知道账单结束的时间,那么可以使用 UNTIL 语法:

2022-02-08 # "Electricity bill [MONTHLY UNTIL 2022-12-31]"
  Expenses:Electricity                      50.10 USD
  Assets:Checking                          -50.10 USD

交易按照年循环,循环 10 次:

2014-03-08 # "Electricity bill [YEARLY REPEAT 10 TIMES]"
  Expenses:Electricity                      50.10 USD
  Assets:Checking                          -50.10 USD

SKIP 语法可以用来跳过某一次记账:

2014-03-08 # "Electricity bill [WEEKLY SKIP 1 TIME REPEAT 10 TIMES]"
  Expenses:Electricity                      50.10 USD
  Assets:Checking                          -50.10 USD

2014-03-08 # "Electricity bill [DAILY SKIP 3 TIMES REPEAT 1 TIME]"
  Expenses:Electricity                      50.10 USD
  Assets:Checking                          -50.10 USD

reference


2022-02-25 beancount , accounting , double-entry

Playbook 使用体验

Playbook 是一个为创意人员而设计的文件管理器,同时强调了非常方便的在线协作能力。Playbook 称自己为 Dropbox for designers。

看其官网的描述就可以知道,Playbook 是为了 Designers,Artist,Photographers,marketer 而设计的。设计师可以用它来管理设计素材,交互设计;艺术家可以用它来管理灵感;摄影师可以用它来分享摄影作品。1

playbook online showcase

在 Playbook 中每一个资源都是使用 Board 来管理,每一个 Board 都在 Playbook 中,所以从上到下的层级关系大概是,Playbook,Board,Sub-Boards, 最后就是要管理的图片资源。

现在注册 Early Access Pro account,可以得到 4TB 的永久存储空间。当然前提是 Playbook 可以一直运营下去。

总结

最后来总结一下 Playbook,一句话说就是产品目前都是在发展阶段,目前只有基于 Web 的管理端,也没有推出任何 Native 的客户端,这也就意味着所有的用户的数据都是在其服务器中,这也就违背了我个人选择软件的第一条原则,由我产生的数据都必须有非常方便可以导出及备份的能力。所以在我这里如果以后要重度使用 Playbook ,那么我也只能将 Playbook 作为一个分享工具来使用。而本地还是保留一个与 Playbook 相似的文件结构来备份这些内容。

初步的使用感受来说,Playbook 非常适合于分享,以及多人协作的场景,如果只是个人使用的话似乎只能用来它作为产出的展示页面。

reference


2022-02-20 playbook , artist , idea , file-manage , photographer , design

利用 ruTorrent 与 rTorrent 限制单独种子的速度

之前的几篇文章就提到过 rTorrent 和 ruTorrent 是我最喜欢的 BT 客户端。之前几篇文章:

今天就再来分享一个非常简单的小技巧,那就是针对个别种子单独进行限速。通常情况下整体的限速,上传和下载,其他的客户端基本上都做得非常完善,基本上是任何一个客户端的基本功能,但是非常少的客户端可以针对个别的种子可以进行限速,而借助 rTorrent 和 ruTorrent 客户端,可以完美的实现。

众所周知有一些私有的 tracker 是会对上传速度做要求的,如果一直以非常高的速度上传可能会被误判,所以非常有必要对个别的种子进行上传的限速。而有些时候可能不希望下载过快以至于占满全部的带宽,尤其是在国内有限的下载带宽的情况下。

Channel

在 rTorrent 和 ruTorrent 的组合中可以通过 Channel 来实现。在 ruTorrent 的设置中,有 Channel 这样一个设定:

rutorrent setting channel

可以看到默认情况下有 10 个不同级别的速度限制,这里以第一条 up16 举例,表示的就是限制上传速度 16Kib/s 而下载不限制。同样 down 的也是类似。

然后在主界面中,右击单个种子就可以看到其中可以对 Channel 设置,比如设置上传不能超过 50MB/s,就可以选择 up50000

rutorrent right click menu

Ratio Rules

如果觉得上面的手动方式比较笨拙的话,ruTorrent 还可以通过 Ratio Rules 来自动设置限速。在菜单栏点击 Plugins,然后选择 Ratio Rules,会展示如下界面。

rutorrent ratio rules

在这个对话框中就可以根据自己的需要设定,如下的条件:

  • Torrent 的标签包含
  • Torrent 的 Tracker URL 包含
  • Tracker 是公开的
  • Tracker 是私有的

当满足这些条件的时候,设置 ratio 以及限速,其中 Set throttle to 就可以选择之前设置的 Channel 中的内容。

当然如果你使用的是 rTorrent 没有使用 ruTorrent 界面,也可以通过配置的方式来实现,这里就不再具体展开。可以参考我之前的文章,以及官网的内容自行设置。

reference


2022-02-19 rtorrent , rutorrent , bittorrent , bt , private-tracker , tracker , bittorrent

电子书

最近文章

  • 在日本生活必备的应用收集整理 在上一篇梳理了一下如何 注册日区的 Apple ID ,其实主要是为了这一篇整理做准备,有很多的应用,如果不是日区就安装不了,并且如果要在日本生活有一些应用还是非常重要的,所以就提前梳理一下需要用到的应用。
  • 如何注册日区 Apple ID 以及初次登录日区 App Store 之前一直使用美区的账号,但突然发现有一些 App 在美区也没有,比如去日本经常需要用到的「乗換案内」就搜不到,美区里面尽是一些冒牌的,还穿插各种广告的应用,还有很多日本本地的一些应用也几乎都没有上架美区。
  • 《工作、消费主义和新穷人》读书笔记 怎么知道的这一本书 前些日子去线下逛书店的时候,在书店刚进门的架子上一眼就看到了这一本,或许是这本书的名字起得太吸引眼球了,但是拿起来之后看到作者才意识到这本书是之前刚刚读过的 [[现代性与大屠杀]] 的作者 [[齐格蒙 鲍曼]] 的著作,这更让我提起了兴趣。
  • 《活法》读书笔记 怎么知道的这一本书 这本书一直非常出名,[[稻盛和夫]] 的名字一直非常响亮,但我似乎对其没有任何了解,这一本书也是非常机缘巧合地在楼下的图书馆里面看到了。
  • Mastodon 站点管理:导入自定义表情包 [[Mastodon]] 实例可以允许站点管理员自定义整站上的表情包,管理的地址在 首选项-管理(Administration)-自定义表情(custom emojis) , 具体的页面地址是 https://instance.domain/admin/custom_emojis。