为 postgrey 添加白名单
在部署一些邮件服务器系统时通常会使用 postgrey 进行灰名单过滤垃圾邮件,这会导致一些陌生域名发来的邮件被延迟很久,可通过添加白名单解决:
编辑 /etc/postgrey/whitelist_clients
, 在其中增加白名单域名。
然后重启服务即可:
systemctl restart postgrey.service
systemctl restart postfix.service
在部署一些邮件服务器系统时通常会使用 postgrey 进行灰名单过滤垃圾邮件,这会导致一些陌生域名发来的邮件被延迟很久,可通过添加白名单解决:
编辑 /etc/postgrey/whitelist_clients
, 在其中增加白名单域名。
然后重启服务即可:
systemctl restart postgrey.service
systemctl restart postfix.service
最近尝试使用 fyne 做一些简单的桌面应用,首先遇到的是中文乱码问题,目前主要有两种方案:
1. 将字体文件打包成 go 文件;
2. 使用 ENV 环境变量。
在安装了 fyne
工具后, 使用 fyne bundle --package xtheme ./fonts/SourceHanSerifSC-VF.ttf > ./app/xtheme/font.go
:
将字体文件 ./fonts/SourceHanSerifSC-VF.ttf
打包到 ./app/xtheme/font.go
文件中,导出的包名为 xtheme
。
生成出的 font.go
文件格式如下:
// auto-generated
// Code generated by '$ fyne bundle'. DO NOT EDIT.
package xtheme
import "fyne.io/fyne/v2"
var resourceSourceHanSerifSCVFTtf = &fyne.StaticResource{
StaticName: "SourceHanSerifSC-VF.ttf",
StaticContent: []byte("\x00\x01..."),
}
package xtheme
import (
"image/color"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/theme"
)
type XTheme struct {
fyne.Theme
}
func (*XTheme) Font(s fyne.TextStyle) fyne.Resource {
return resourceSourceHanSerifSCVFTtf
}
func (m *XTheme) Size(name fyne.ThemeSizeName) float32 {
return theme.DefaultTheme().Size(name)
}
func (m XTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {
return theme.DefaultTheme().Color(name, variant)
}
func (m XTheme) Icon(name fyne.ThemeIconName) fyne.Resource {
return theme.DefaultTheme().Icon(name)
}
在应用中使用 SetTheme()
方法设置自定义的主题。
a := app.New()
a.Settings().SetTheme(&xtheme.XTheme{})
使用 github.com/flopp/go-findfont
这个库来通过环境变量查找字体。
import (
"github.com/flopp/go-findfont"
"github.com/golang/freetype/truetype"
)
func main(){
fontFilePath := "./fonts/SourceHanSerifSC-VF.ttf" //
fontPath, e := findfont.Find(fontFilePath)
if e != nil {
panic(e)
}
fmt.Printf("Found 'fontFile' in '%s'\n", fontPath)
fontData, e := os.ReadFile(fontPath)
if e != nil {
panic(e)
}
_, e = truetype.Parse(fontData)
if e != nil {
panic(e)
}
os.Setenv("FYNE_FONT", fontPath)
os.Setenv("FYNE_FONT_MONOSPACE", fontPath) // 注意:如果不设置这个环境变量会导致 widget.TextGrid 中的中文乱码
}
关于 TextGrid
组件的中文乱码问题:
在网上查到的设置环境变量的方式基本都是只设置了 FYNE_FONT_MONOSPACE
这个环境变量,
设置后 widget.TextGrid
组件内的中文仍然是乱码(其它组件内的中文能正常显示),并且通过打包字体文件到 go 文件的方式也不会对 widget.TextGrid
生效,
直到设置了 FYNE_FONT_MONOSPACE
环境变量后才解决了 TextGrid
组件的中文乱码问题。
直接交叉编译时,会提示 build constraints exclude all Go files in /path/go/pkg/mod/github.com/go-gl/gl@..
的错误。编译时添加环境变量 CGO_ENABLED=1
后,提示错误 gcc_libinit_windows.c:8:10: fatal error: 'windows.h' file not found
。
解决方法:
安装 mingw-w64
: brew install mingw-w64
编译:
env CC=x86_64-w64-mingw32-gcc CGO_ENABLED=1 GOOS=windows GOARCH=amd64 go build -o 'bin/project_gui.exe'
viem: TypeScript Interface for Ethereum https://github.com/wevm/viem
更换手机时,忘记备份 MFA 代码,无法登录 Oracle Cloud 网站。 解决方法: 在 Oracle Cloud 网站登录,输入邮箱密码后,会跳到一个类似如下的网址
https://idcs-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.identity.oraclecloud.com/ui/v1/signin
获取网址中 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
的值,将其替换在如下网址中进行访问:
https://idcs-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.identity.oraclecloud.com/ui/v1/myconsole?root=my-info&my-info=my_profile_security
在此页面可生成新的绕过码、修改密码、管理其它的两步认证,或进行其它安全设置。
(其实我有点好奇为什么会有这样的东西存在)
使用 puppeteer
操作 MetaMask
钱包时,能进行对指定元素进行点击、输入等操作,但使用 page.$()
之类的方法获取元素时,报错:
Error: Evaluation failed: Error: LavaMoat - property "Map" of globalThis is inaccessible under scuttling mode. To learn more visit https://github.com/LavaMoat/LavaMoat/pull/360.
at get (chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/runtime-lavamoat.js:11200:17)
解决方法:
修改扩展目录的 runtime-lavamoat.js
文件:
const {
scuttleGlobalThis,
scuttleGlobalThisExceptions,
} = { "scuttleGlobalThis": true, "others...": "" }
将此处的 scuttleGlobalThis
改为 false
即可。
替换掉了 iptables。
配置文件 /etc/nftables.conf
:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0;
# 允许已建立的连接
ct state established,related accept
# 允许回环接口(本地访问)
iif lo accept
# 允许 SSH 连接(如果需要)
tcp dport 22 accept
# 允许 DNS 查询(来自特定 IP)
ip saddr 209.123.1.15 tcp dport {53, 80, 443} accept
ip saddr 209.123.1.15 udp dport {53, 80, 443} accept
ip saddr 38.100.10.10 tcp dport {53, 80, 443} accept
ip saddr 38.100.10.10 udp dport {53, 80, 443} accept
# 默认禁止:
tcp dport {53, 80, 443} drop
udp dport {53, 80, 443} drop
}
chain forward {
type filter hook forward priority 0;
}
chain output {
type filter hook output priority 0;
}
}
重载配置: nft -f /etc/nftables.conf
WireGuard 配置中排除局域网 IP:
AllowedIPs = ::/0, 1.0.0.0/8, 2.0.0.0/8, 3.0.0.0/8, 4.0.0.0/6, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/2, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 1.1.1.1/32, 8.8.8.8/32
puppeteer
中设置代理的认证方式居然不是 browser
级别的, 而是 page
级别的 -_-
import puppeteer, { Browser, Page, ElementHandle } from 'puppeteer';
import * as utils from "./utils";
(async () => {
const chromeDataDir = './_chrome_data/temp-test';
let browser = await puppeteer.launch({
headless: false,
userDataDir: chromeDataDir,
devtools: false,
args: [
`--disable-web-security`,
// '--disable-site-isolation-trials',
// `--disable-extensions-except=${extensionPath}`,
// `--load-extension=${extensionPath}`,
// `--no-sandbox`,
`--proxy-server=123.1.1.1:9527`
],
});
let page = await browser.newPage();
await page.authenticate({ username: 'user-001', password: 'XXnKPccc' })
await page.goto('https://ip.sb');
await utils.sleepMinutes(999);
})();
在使用 puppeteer
操作 chrome 浏览器时,
当唤起浏览器插件时,无法在插件页面读、写剪贴板,
似乎这是个 bug:
很多时候写框架的人关注的是性能、可扩展性之类的东东, 但写业务逻辑的更关注如何方便的实现某个功能。
Creating and Signing a SegWit Transaction from Scratch:
https://medium.com/coinmonks/creating-and-signing-a-segwit-transaction-from-scratch-ec98577b526a
MySQL 8 中使用 JSON_TABLE 创建 JSON 临时表进行 JSON 复杂查询
比如有个用户表信息表,使用 plans
字段存储了用户的套餐信息,这个表长这样:
mysql> SELECT id,email,plans from users ;
+-------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------+
| id | email | plans |
+-------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------+
| 10000 | t0@t0.com | [{"id": 101, "name": "套餐1", "expired_at": "2024-05-01 10:12:31"}, {"id": 102, "name": "套餐2", "expired_at": "2024-08-05 07:41:16"}] |
| 10001 | t1@t1.com | [{"name": "套餐2", "expired_at": "2023-12-11 05:07:11"}, {"name": "套餐3", "expired_at": "2023-11-08 16:02:51"}] |
| 10002 | t2@t2.com | [{"name": "套餐4", "expired_at": "2024-01-20 17:24:33"}] |
+-------+-----------+--------------------------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)
想要根据 plans
字段 JSON 数组中的 name
字段获取指定套餐的用户及到期时间,但这里试图使用 JSON_EXTRACT(plans, '$[n].expired_at')
提取 JSON 中的字段时却无法知道索引 n
的值的。
这种情况可以使用 JSON_TABLE
将 JSON 数组中的值创建临时表来解决:
mysql> SELECT
-> u.id,
-> u.email,
-> json_tab.plan_name,
-> json_tab.plan_expired_at
-> FROM
-> users AS u
-> CROSS JOIN JSON_TABLE(
-> `plans`, '$[*]'
-> COLUMNS (
-> plan_id INT PATH '$.id' ERROR ON ERROR,
-> plan_name VARCHAR(40)PATH '$.name',
-> plan_expired_at datetime PATH '$.expired_at'
-> )
-> ) AS json_tab
-> WHERE
-> plan_name = '套餐2';
+-------+-----------+-----------+---------------------+
| id | email | plan_name | plan_expired_at |
+-------+-----------+-----------+---------------------+
| 10000 | t0@t0.com | 套餐2 | 2024-08-05 07:41:16 |
| 10001 | t1@t1.com | 套餐2 | 2023-12-11 05:07:11 |
+-------+-----------+-----------+---------------------+
2 rows in set (0.00 sec)
薅了一个甲骨文的免费机器,在控制面板设置了开放端口后居然还连接不上。 似乎它预置的 Ubuntu 镜像默认是关闭了所有端口需要安装防火墙打开?
sudo apt install firewalld
sudo firewall-cmd --zone=public --permanent --add-port=9090/tcp
sudo firewall-cmd --zone=public --permanent --add-port=9090/udp
sudo firewall-cmd --reload
在 Caddyfile 中可以先定义一个名为 log 的配置模板,并且在配置模板内使用传入的参数来对每个站点使用不同的目录。
各站点导入模板并传入自己的参数即可。
(log) {
log {
output file /log/{args.0}/access.log {
roll_size 100MiB
roll_local_time
roll_keep 10
roll_keep_for 2160h
}
}
}
a.example.com {
import log a-site-log
}
b.example.com {
import log b-site-log
}
最近一直想做一份好吃的青菜炒牛肉。
想做出记忆中的味道,
然而尝试了多次都未成功。
小时候有一次在舅舅家,村里有头牛从山上摔下摔死了,
那天晚上我吃了一顿记忆中最好吃的青菜牛肉,
但我已经记不清它具体是啥味了,
甚至也记不清到底是用的啥青菜一起做的了。
Go 使用大小写来决定结构体中字段是否导出真的很蛋疼,当我需要用 gob
序列化某个结构体时不得不进行大量重命名…
最近维护了两个几年前的代码,突然意识到 Go 语言这种非常依赖 github 之类的仓库来管理第三方依赖的方式非常不靠谱啊。
一不小心某个依赖库就没了…
使用 frp 的 stcp 方式进行流量转发比起 直接使用 tcp 的方式相对增加了一些安全性,但也更繁琐(除了在受控机需要安装 frp 外还需要在主控方也安装)。
主控机
[common]
server_addr = 1.2.3.4
server_port = 7000
[secret_ssh]
type = stcp
# stcp 的访问者身份: 'server' or 'visitor'
role = visitor
# 要访问的 stcp 代理的名字
server_name = secret_ssh
# sk 需要与受控机需要保持一致
sk = MY_SK
# 绑定本地端口用于访问 SSH 服务
bind_addr = 127.0.0.1
bind_port = 6000
受控机:
[common]
server_addr = 1.2.3.4
server_port = 7000
[secret_ssh]
type = stcp
sk = MY_SK
local_ip = 127.0.0.1
local_port = 22
然后就可以在主控机上通过 ssh -oPort=6000 ubuntu@127.0.0.1
连接到受控机的 22 端口