Skip to content

Commit 32e9143

Browse files
committed
MGJW: 20250412 - 本周内容完成 - 感觉还不少
Signed-off-by: LetMeFly666 <[email protected]>
1 parent 8085e67 commit 32e9143

File tree

8 files changed

+1472
-1
lines changed

8 files changed

+1472
-1
lines changed

tryGoPy/MGJW/thisWeek/beacon.tfsp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"email": "20250412\u5f53\u65e5\u6307\u4ee4",
4+
"beacon_id": "5136bbc90ee82af739d34dc91b947d2a18a61a59aece886fca117c9245573ef830f910ff742e5062010ca38a4b44cd9b"
5+
}
6+
]

tryGoPy/MGJW/thisWeek/chat.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
flask写一个简单的web服务实现一个邮件与信标id的对应功能实现以下功能
2+
1. 前端用户可以输入一些文本这些文本会传到后端并以aes加密作为信标id并显示在前端界面上
3+
2. 前端用户可以查看邮件文本与信标id的一一对应关系列表
4+
3. 数据存储使用简单的写入和读取json文件即可
5+
6+
其中加密算法可参考
7+
def encrypt_aes(plaintext: str, key: bytes) -> bytes:
8+
cipher = AES.new(key, AES.MODE_CBC) # 使用CBC模式
9+
ct_bytes = cipher.encrypt(pad(plaintext.encode(), AES.block_size))
10+
return cipher.iv + ct_bytes # 返回IV + 密文

tryGoPy/MGJW/thisWeek/count.tfsp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"1a8c06cbcd61e779f815d36369ce04b9c105f94d58dca2eb65bf08ef4af993cdc38b9e4e456e56a9fe8fd1e1a3212e78": 3}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
'''
2+
Author: LetMeFly
3+
Date: 2025-04-12 20:05:18
4+
LastEditors: LetMeFly.xyz
5+
LastEditTime: 2025-04-12 20:24:57
6+
'''
7+
from flask import Flask, render_template, request, redirect, url_for
8+
from Crypto.Cipher import AES
9+
from Crypto.Util.Padding import pad
10+
# import base64
11+
import json
12+
import os
13+
14+
15+
app = Flask('LetMeFly_xyz - Flask(MGJW) - beacon')
16+
17+
KEY = bytes.fromhex('e3a9a39b3c95c109257aeb8c09cb8ad331779647c54de1a40a66d308f8e4a882') # 演示用,实际可别公布
18+
DATA_FILE = 'beacon.tfsp'
19+
20+
21+
def encrypt_aes(plaintext: str, key: bytes) -> bytes:
22+
cipher = AES.new(key, AES.MODE_CBC)
23+
ct_bytes = cipher.encrypt(pad(plaintext.encode(), AES.block_size))
24+
return cipher.iv + ct_bytes
25+
26+
27+
def load_data():
28+
if not os.path.exists(DATA_FILE):
29+
return []
30+
with open(DATA_FILE, 'r') as f:
31+
return json.load(f)
32+
33+
34+
def save_data(data):
35+
with open(DATA_FILE, 'w') as f:
36+
json.dump(data, f, indent=2)
37+
38+
39+
@app.route('/', methods=['GET', 'POST'])
40+
def index():
41+
beacon_id = None
42+
if request.method == 'POST':
43+
email = request.form['email']
44+
encrypted = encrypt_aes(email, KEY)
45+
# beacon_id = base64.b64encode(encrypted).decode('utf-8') # 算了,还是先不base64了
46+
beacon_id = encrypted.hex()
47+
48+
data = load_data()
49+
data.append({
50+
"email": email,
51+
"beacon_id": beacon_id
52+
})
53+
save_data(data)
54+
55+
return render_template('server-beacon-index.html', beacon_id=beacon_id)
56+
57+
58+
@app.route('/list')
59+
def show_list():
60+
data = load_data()
61+
return render_template('server-beacon-list.html', entries=data)
62+
63+
64+
if __name__ == '__main__':
65+
app.run(debug=True)
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
'''
2+
Author: LetMeFly
3+
Date: 2025-03-21 15:44:59
4+
LastEditors: LetMeFly.xyz
5+
LastEditTime: 2025-04-12 19:55:01
6+
'''
7+
from flask import Flask, request, send_file
8+
import io
9+
from Crypto.Cipher import AES
10+
from Crypto.Util.Padding import unpad
11+
from binascii import unhexlify
12+
import os
13+
import json
14+
15+
16+
app = Flask('LetMeFly_xyz - Flask(MGJW)')
17+
18+
# 1x1像素的PNG图片
19+
minimal_image = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDAT\x08\xd7c\xf8\x0f\x00\x01\x01\x01\x00\x1f\x9d\x8e\xf4\x00\x00\x00\x00IEND\xaeB`\x82'
20+
21+
22+
# 初始化时读取历史信息,断电恢复也不怕哈哈哈,但是没有考虑并发问题(虽然现实生活中用户很难快速打开一封邮件并触发信标两次)。
23+
if os.path.exists('count.tfsp') and os.path.isfile('count.tfsp'):
24+
with open('count.tfsp', 'r') as f:
25+
data = json.loads(f.read())
26+
else:
27+
data = {}
28+
29+
30+
def decrypt_aes(ciphertext: str) -> str:
31+
ciphertext = unhexlify(ciphertext)
32+
key = bytes.fromhex('e3a9a39b3c95c109257aeb8c09cb8ad331779647c54de1a40a66d308f8e4a882') # 演示用
33+
iv = ciphertext[:AES.block_size]
34+
ct = ciphertext[AES.block_size:] # 密文
35+
cipher = AES.new(key, AES.MODE_CBC, iv)
36+
pt = unpad(cipher.decrypt(ct), AES.block_size)
37+
return pt.decode()
38+
39+
40+
@app.route('/image', methods=['GET'])
41+
def get_image():
42+
# 获取查询参数
43+
jwt = request.args.get('jwt', default='', type=str)
44+
print(jwt)
45+
global data
46+
if jwt in data:
47+
data[jwt] += 1
48+
else:
49+
data[jwt] = 1
50+
with open('count.tfsp', 'w') as f:
51+
f.write(json.dumps(data))
52+
decrypted = decrypt_aes(jwt)
53+
print(decrypted)
54+
# 返回图片
55+
return send_file(
56+
io.BytesIO(minimal_image),
57+
mimetype='image/png',
58+
as_attachment=False
59+
)
60+
61+
62+
@app.route('/count')
63+
def get_count():
64+
jwt = request.args.get('jwt', default='', type=str)
65+
print(jwt)
66+
if jwt in data:
67+
return str(data[jwt])
68+
return str(0)
69+
70+
71+
@app.route('/')
72+
def index():
73+
return "Hello World"
74+
75+
76+
if __name__ == '__main__':
77+
# app.run(ssl_context="adhoc", debug=True, host='narc.letmefly.xyz', port=86)
78+
app.run(debug=True)
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<!--
2+
* @Author: LetMeFly
3+
* @Date: 2025-04-12 20:09:35
4+
* @LastEditors: LetMeFly.xyz
5+
* @LastEditTime: 2025-04-12 20:22:26
6+
-->
7+
<!-- templates/index.html -->
8+
<!DOCTYPE html>
9+
<html lang="zh-CN">
10+
<head>
11+
<meta charset="UTF-8">
12+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
13+
<title>生成信标ID</title>
14+
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
15+
<style>
16+
:root {
17+
--primary-color: #4361ee;
18+
--secondary-color: #3a0ca3;
19+
--accent-color: #f72585;
20+
--light-bg: #f8f9fa;
21+
--dark-text: #2b2d42;
22+
--light-text: #f8f9fa;
23+
--border-radius: 8px;
24+
--box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
25+
}
26+
27+
body {
28+
font-family: 'Roboto', 'Segoe UI', sans-serif;
29+
line-height: 1.6;
30+
color: var(--dark-text);
31+
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
32+
margin: 0;
33+
padding: 0;
34+
min-height: 100vh;
35+
display: flex;
36+
flex-direction: column;
37+
align-items: center;
38+
padding: 20px;
39+
}
40+
41+
.container {
42+
width: 100%;
43+
max-width: 800px;
44+
background: white;
45+
border-radius: var(--border-radius);
46+
box-shadow: var(--box-shadow);
47+
padding: 40px;
48+
margin-top: 30px;
49+
}
50+
51+
h1 {
52+
color: var(--primary-color);
53+
text-align: center;
54+
margin-bottom: 30px;
55+
font-weight: 500;
56+
position: relative;
57+
}
58+
59+
h1::after {
60+
content: '';
61+
display: block;
62+
width: 60px;
63+
height: 4px;
64+
background: var(--accent-color);
65+
margin: 10px auto 0;
66+
border-radius: 2px;
67+
}
68+
69+
form {
70+
margin: 30px 0;
71+
}
72+
73+
textarea {
74+
width: 100%;
75+
height: 150px;
76+
padding: 15px;
77+
border: 2px solid #e9ecef;
78+
border-radius: var(--border-radius);
79+
font-family: inherit;
80+
font-size: 16px;
81+
resize: vertical;
82+
transition: all 0.3s ease;
83+
margin: 15px 0;
84+
}
85+
86+
textarea:focus {
87+
border-color: var(--primary-color);
88+
box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.2);
89+
outline: none;
90+
}
91+
92+
button {
93+
background-color: var(--primary-color);
94+
color: white;
95+
border: none;
96+
padding: 12px 24px;
97+
font-size: 16px;
98+
font-weight: 500;
99+
border-radius: var(--border-radius);
100+
cursor: pointer;
101+
transition: all 0.3s ease;
102+
display: block;
103+
width: 100%;
104+
max-width: 200px;
105+
margin: 20px auto;
106+
}
107+
108+
button:hover {
109+
background-color: var(--secondary-color);
110+
transform: translateY(-2px);
111+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
112+
}
113+
114+
.result-section {
115+
margin: 40px 0;
116+
padding: 25px;
117+
background-color: var(--light-bg);
118+
border-radius: var(--border-radius);
119+
border-left: 4px solid var(--accent-color);
120+
}
121+
122+
h3 {
123+
color: var(--secondary-color);
124+
margin-top: 0;
125+
}
126+
127+
.beacon-id {
128+
word-break: break-all;
129+
padding: 15px;
130+
background: white;
131+
border-radius: var(--border-radius);
132+
font-family: 'Courier New', monospace;
133+
border: 1px solid #e9ecef;
134+
margin-top: 15px;
135+
}
136+
137+
.nav-link {
138+
display: inline-block;
139+
margin-top: 20px;
140+
color: var(--primary-color);
141+
text-decoration: none;
142+
font-weight: 500;
143+
transition: all 0.3s ease;
144+
padding: 8px 0;
145+
border-bottom: 2px solid transparent;
146+
}
147+
148+
.nav-link:hover {
149+
color: var(--accent-color);
150+
border-bottom-color: var(--accent-color);
151+
}
152+
153+
@media (max-width: 768px) {
154+
.container {
155+
padding: 25px;
156+
}
157+
158+
textarea {
159+
height: 120px;
160+
}
161+
162+
button {
163+
max-width: 100%;
164+
}
165+
}
166+
</style>
167+
</head>
168+
<body>
169+
<div class="container">
170+
<h1>生成信标ID</h1>
171+
172+
<form method="POST">
173+
<textarea name="email" placeholder="请输入邮件文本内容..." required></textarea>
174+
<button type="submit">生成信标ID</button>
175+
</form>
176+
177+
{% if beacon_id %}
178+
<div class="result-section">
179+
<h3>生成结果:</h3>
180+
<div class="beacon-id">{{ beacon_id }}</div>
181+
</div>
182+
{% endif %}
183+
184+
<a href="{{ url_for('show_list') }}" class="nav-link">查看所有记录 →</a>
185+
</div>
186+
</body>
187+
</html>

0 commit comments

Comments
 (0)