一次精彩的助攻

前一阵得到一笔意外收入,为了在葫芦娃俱乐部踢的更开心,和老边商量决定买一个xbot足球比赛录像设备。

开始用着感觉不错,但是有两点挺鸡肋,一是这个设备不能自己录像,设备只提供运动跟踪和云台功能,录像需要用手机的摄像头,这样就需要占用手机,如果被电话等程序打断,录制有可能中断。二是如果想快速剪辑,就需要在录像的时候用遥控器操作打点,这样如果我在场上踢比赛,是无法操作的,没有打点记录,剪辑的时候时间成本就比较高了。

但是,昨天的比赛中,当他录到我的一个高光时刻的时候,我对他的印象分又提高了不少。

请欣赏这一记精彩的后脚跟磕球助攻。

现在的两个解决方案:

  • 录像现在直接传到B站,清晰度,速度都可以接受,这样不剪辑也可以。录制完直接传,占用不了多少时间。

  • 视频录像上有实时的时间水印,这一点比较好,那么就需要在精彩时刻发生的时候,想办法快速的记录下时间,并且编辑的时候,直接补打上点,就可以快速的剪辑出来精彩集锦了。

所以目前唯一的不足,是如何在场上踢球的时候,也能多次快速的记录下准确的时间呢?

一段空档期

无锡的项目搞的差不多了,从忙碌的疯狂进代码的阶段进入了短暂的空闲期。
啤酒城的项目今年没有啥大的改动,等合同敲定,活动开业前,把服务器重新部署上线即可。
不夜城街区的项目,肥城的已经完成,等剑阁项目和临夏项目开业,服务器部署一下,活也不是太多。

那么,得琢磨个事情干干,这段空档期干点啥好呢~

version
软件的版本,又何尝不是人生的版本呢?

阿里的云小店

最近在把分散在各地的项目进行了整合,计划合并到一个服务器上,搬家工作搞了整整一天。

研究了一番,最后把去年项目剩的服务器全给取消了,买了一个阿里云的云小站 https://www.aliyun.com/minisite/goods 的ECS。

配置有两种:

  1. 2核2G,3M固定带宽,40G ESSD Entry云盘 ¥99.00/1年起 官网折扣价: ¥956.64/1年

  2. 2核4G,5M固定带宽,80G ESSD Entry云盘 ¥199.00/1年起 官网折扣价: ¥2507.70/1年

物超所值,几乎不到1折的价格,更重要的是,能不限年限的续费,一个账户只能嫖一个。

直接199的配置走起,2核4G完全够用。跑了两个Python Flask, 两个Python FastAPI, 两个静态site,还能剩余2.2G内存,妥妥够用。

感谢阿里云~

prettier格式化代码

PyCharm里如果有js, html 和css文件,社区版本的IDE是不能直接格式化这些静态文件,需要专业版的来实现。
所以,可以尝试在terminal里直接使用prettier格式化代码。

1
2
3
4
5
6
7
# 用node全局安装
npm install -g prettier

# 格式化项目里的所有的js,jsx,ts,tsx,css,html,json
# 在宽屏幕下,可以设置代码的折行宽度大一些,在我的屏幕上180是个不错的选择。
npx prettier --write "**/*.{js,jsx,ts,tsx,css,html,json}" --print-width 180

@lru_cached装饰器实现全局配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from functools import lru_cache

from fastapi import Depends, FastAPI
from typing_extensions import Annotated

from . import config

app = FastAPI()


@lru_cache
def get_settings():
return config.Settings()


@app.get("/info")
async def info(settings: Annotated[config.Settings, Depends(get_settings)]):
return {
"app_name": settings.app_name,
"admin_email": settings.admin_email,
"items_per_user": settings.items_per_user,
}

使用了 @lru_cache 装饰器,因此只有在第一次调用它时,才会创建 Settings 对象一次。
然后,在下一次请求的依赖项中对 get_settings() 进行任何后续调用时,它不会执行 get_settings() 的内部代码并创建新的 Settings 对象,而是返回在第一次调用时返回的相同对象,一次又一次。

@lru_cache 技术细节

@lru_cache 修改了它所装饰的函数,以返回第一次返回的相同值,而不是再次计算它,每次都执行函数的代码。
因此,下面的函数将对每个参数组合执行一次。然后,每个参数组合返回的值将在使用完全相同的参数组合调用函数时再次使用。

对于我们的依赖项 get_settings(),该函数甚至不接受任何参数,因此它始终返回相同的值。

这样,它的行为几乎就像是一个全局变量。但是由于它使用了依赖项函数,因此我们可以轻松地进行测试时的覆盖。

@lru_cache 是 functools 的一部分,它是 Python 标准库的一部分,可以在 Python 文档 lru_cache中了解有关 @lru_cache 的更多信息。

时差攻击

今天学习FastAPI时,细致了解了一下时差攻击。

时差攻击

什么是时差攻击?

假设攻击者试图猜出用户名与密码。

他们发送用户名为 johndoe,密码为 love123 的请求。

然后,Python 代码执行如下操作:

1
2
if "johndoe" == "stanleyjobson" and "love123" == "swordfish":
...

但就在 Python 比较完 johndoe 的第一个字母 j 与 stanleyjobson 的 s 时,Python 就已经知道这两个字符串不相同了,它会这么想,没必要浪费更多时间执行剩余字母的对比计算了。应用立刻就会返回错误的用户或密码。

但接下来,攻击者继续尝试 stanleyjobsox 和 密码 love123。

应用代码会执行类似下面的操作:

1
2
if "stanleyjobsox" == "stanleyjobson" and "love123" == "swordfish":
...

此时,Python 要对比 stanleyjobsox 与 stanleyjobson 中的 stanleyjobso,才能知道这两个字符串不一样。因此会多花费几微秒来返回错误的用户或密码。

反应时间对攻击者的帮助

通过服务器花费了更多微秒才发送错误的用户或密码响应,攻击者会知道猜对了一些内容,起码开头字母是正确的。

然后,他们就可以放弃 johndoe,再用类似 stanleyjobsox 的内容进行尝试。

专业攻击

当然,攻击者不用手动操作,而是编写每秒能执行成千上万次测试的攻击程序,每次都会找到更多正确字符。

但是,攻击者利用时间差,就能在几分钟或几小时内,以这种方式猜出正确的用户名和密码。

使用 secrets.compare_digest() 修补

在此,代码中使用了 secrets.compare_digest()。

简单的说,它使用相同的时间对比 stanleyjobsox 和 stanleyjobson,还有 johndoe 和 stanleyjobson。对比密码时也一样。

在代码中使用 secrets.compare_digest() ,就可以安全地防御全面攻击了。

1
2
3
4
5
6
7
8
9
10
current_username_bytes = credentials.username.encode("utf8")
correct_username_bytes = b"stanleyjobson"
is_correct_username = secrets.compare_digest(
current_username_bytes, correct_username_bytes
)
current_password_bytes = credentials.password.encode("utf8")
correct_password_bytes = b"swordfish"
is_correct_password = secrets.compare_digest(
current_password_bytes, correct_password_bytes
)

Ruff格式化Python代码可真好用

发现了一个非常好用的代码格式化工具:Ruff

Ruff是一个基于Python的代码格式化工具,它可以帮助开发者格式化Python代码,使其符合PEP 8标准。

Pip安装:

1
pip install ruff

使用:

1
ruff format <file>

把所有的项目都用ruff格式化了一遍,快到难以想象,几百个文件的项目,一两秒钟就格式化好了。

CS自动购买配置

闲来无事打了一会CS,发现自动购买按了F1以后,只买了主武器,甚至子弹都没有补满,研究了一下发现游戏文件里有个/cstrike/autobuy.txt文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// This list of "buy aliases" is used by the AutoBuy system.
// The system begins with the first alias in the list, and attempts to purchase it.
// If a primary weapon is successfully purchased, all later primary weapon aliases are skipped.
// Similarly, secondary weapon buy alias are skipped once a seconary weapon has been purchased.
// You can customize this file to reflect your weapon and equipment preferences and priorities.
//
// The console command for autobuy is "autobuy"
//
// The available buy aliases and their names as shown on the buy menu are:
// (Many weapons have more than one buy alias)
//
// galil - IDF Defender
// defender - IDF Defender
// ak47 - CV-47
// cv47 - CV-47
// scout - Schmidt Scout
// sg552 - Krieg 552
// krieg552 - Krieg 552
// awp - Magnum Sniper Rifle
// magnum - Magnum Sniper Rifle
// g3sg1 - D3/AU1
// d3au1 - D3/AU1
// famas - Clarion 5.56
// clarion - Clarion 5.56
// m4a1 - Maverick M4A1 Carbine
// aug - Bullpup
// bullpup - Bullpup
// sg550 - Krieg 550 Commando
// krieg550 - Krieg 550 Commando
// glock - 9x19mm Sidearm
// 9x19mm - 9x19mm Sidearm
// usp - KM .45 Tactical
// km45 - KM .45 Tactical
// p228 - 228 Compact
// 228compact - 228 Compact
// deagle - Night Hawk .50C
// nighthawk - Night Hawk .50C
// elites - .40 Dual Elites
// fn57 - ES Five-Seven
// fiveseven - ES Five-Seven
// m3 - Leone 12 Gauge Super
// 12gauge - Leone 12 Gauge Super
// xm1014 - Leone YG1265 Auto Shotgun
// autoshotgun - Leone YG1265 Auto Shotgun
// mac10 - Ingram MAC-10
// tmp - Schmidt Machine Pistol
// mp - Schmidt Machine Pistol
// mp5 - KM Sub-Machine Gun
// smg - KM Sub-Machine Gun
// ump45 - KM UMP45
// p90 - ES C90
// c90 - ES C90
// m249 - M249
// primammo - Primary Ammo
// secammo - Secondary Ammo
// vest - Kevlar
// vesthelm - Kevlar+Helmet
// flash - Flashbang
// hegren - HE Grenade
// sgren - Smoke Grenade
// nvgs - Nightvision
// defuser - Defusal Kit
// shield - Tactical Shield

m4a1
ak47
famas
galil
p90
mp5

primammo
secammo

defuser
flash
flash
hegren
sgren

vesthelm
vest

这里面定义了自动购买的时候要买的武器和装备,直接改一下,增加一下需要的配置就可以了,闪光灯这里买两个。
保存文件,重新启动游戏就可以了。

页面烟花特效

在一个历史项目上有一个新需求,当客流到达一定整万数的时候,来一个页面特殊效果,于是决定做一个烟花的效果出来。
研究了一下,找到一个项目 https://www.kirilv.com/canvas-confetti/ ,最后的实现效果还不错。

点这里查看演示效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>烟花效果</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
</head>
<style>
#message {
font-size: 100px;
font-weight: bold;
color: #fff;
position: fixed; /* 全屏覆盖 */
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
z-index: 50;

/* 半透明背景 */
background-color: rgba(0, 0, 0, 0.7); /* 黑色半透明背景 */
/* 文字变色效果 */
animation: color-change 2s infinite; /* 3秒变色循环 */
}

/* 文字颜色变换动画 */
@keyframes color-change {
0% {
color: #ff3333; /* 鲜红 */
}
25% {
color: #DC143C; /* 浅红 */
}
50% {
color: #FF1493; /* 桃红 */
}
75% {
color: #8B0000; /* 深红 */
}
100% {
color: #ff3333; /* 回到鲜红 */
}
}
</style>
<body>

<div id="message" style="display: none;"></div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.9.3/dist/confetti.browser.min.js"></script>

<script>

function showCelebration(number) {
const duration = 43000;
const endTime = Date.now() + duration;
const colors = ['#bb0000', '#ff00ff', '#00bbff', '#00ff00', '#ffff00', '#ff8800'];

// 显示文字
const messageDiv = document.getElementById('message');
messageDiv.innerHTML = `热烈庆贺客流总数突破<br><br>${number}`;
$(messageDiv).fadeIn(500);

function randomInRange(min, max) {
return Math.random() * (max - min) + min;
}

function launchFireworks() {
(function frame() {
confetti({
particleCount: 6,
angle: 60,
spread: 55,
origin: { x: 0 },
colors: colors
});
confetti({
particleCount: 6,
angle: 120,
spread: 55,
origin: { x: 1 },
colors: colors
});

if (Date.now() < endTime) {
requestAnimationFrame(frame);
}
})();
}

function launchCentralExplosions() {
const interval = setInterval(() => {
for (let i = 0; i < 3; i++) {
setTimeout(() => {
confetti({
spread: 360,
ticks: 120,
gravity: 0,
decay: 0.94,
startVelocity: 20,
colors: ['#ff4500', '#ff6347', '#ffd700'], // 橙红、番茄红、金色
particleCount: 60,
scalar: 1.2,
origin: {
x: randomInRange(0.4, 0.6), // 随机横向位置
y: randomInRange(0.4, 0.6), // 随机纵向位置
},
shapes: ['star', 'circle']
});
}, i * 200);
}
}, 2000);

setTimeout(() => {
clearInterval(interval);
}, duration);
}

// 启动特效
launchFireworks();
launchCentralExplosions();

// 在25秒后隐藏文字和停止特效
setTimeout(() => {
$(messageDiv).fadeOut(500);
}, duration);
}

showCelebration(60000000);

</script>
</body>
</html>


做完这个以后,后面发现还有一个朋友 Caleb Miller 做的几乎一比一仿真的烟花效果,记录一下。
https://codepen.io/MillerTime/pen/XgpNwb

常用的git alias

重装了一次电脑,记录一下git alias的配置。

1
2
3
4
5
6
7
8
9
$ cat ~/.gitconfig 
[user]
name = Jinloh WU
email = i@tiaobug.com
[alias]
lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
ac = !git add . && git commit -m
acp = "!f() { git add . && git commit -m \"$1\" && git push; }; f"
acpg = "!f() { git add . && git commit -m \"$1\" && git push && git push github; }; f"

顺手记录一下:
Thinkbook 14+ 使用U盘启动的时候,F12以后引导选择后,无法正常启动。需要F1选择把安全启动模式给关掉就可以了。


Powered by Hexo and Hexo-theme-hiker

Copyright © 2012 - 2025 tiaobug.com All Rights Reserved.

鲁ICP备2024124237号-1