Skip to content

Commit e00c5b1

Browse files
committed
fix: use crypto/rand
1 parent dc6543a commit e00c5b1

File tree

3 files changed

+280
-7
lines changed

3 files changed

+280
-7
lines changed

ui/src/pages/admin/tabs/Search.tsx

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
import React, { useState } from 'react';
2+
import {
3+
Table,
4+
Button,
5+
Modal,
6+
Form,
7+
Input,
8+
Space,
9+
message,
10+
Upload,
11+
Image,
12+
} from 'antd';
13+
import { DragOutlined, DeleteOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons';
14+
import { DndContext } from '@dnd-kit/core';
15+
import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
16+
import { CSS } from '@dnd-kit/utilities';
17+
18+
interface SearchEngine {
19+
id: string;
20+
name: string;
21+
baseUrl: string;
22+
queryParam: string;
23+
logo: string;
24+
order: number;
25+
}
26+
27+
const defaultEngines: SearchEngine[] = [
28+
{
29+
id: '1',
30+
name: '百度',
31+
baseUrl: 'https://www.baidu.com/s',
32+
queryParam: 'wd',
33+
logo: 'https://www.baidu.com/favicon.ico',
34+
order: 1,
35+
},
36+
{
37+
id: '2',
38+
name: 'Google',
39+
baseUrl: 'https://www.google.com/search',
40+
queryParam: 'q',
41+
logo: 'https://www.google.com/favicon.ico',
42+
order: 2,
43+
},
44+
{
45+
id: '3',
46+
name: 'Bing',
47+
baseUrl: 'https://www.bing.com/search',
48+
queryParam: 'q',
49+
logo: 'https://www.bing.com/favicon.ico',
50+
order: 3,
51+
},
52+
];
53+
54+
const DraggableRow = ({ children, ...props }: any) => {
55+
const {
56+
attributes,
57+
listeners,
58+
setNodeRef,
59+
transform,
60+
transition,
61+
isDragging,
62+
} = useSortable({
63+
id: props['data-row-key'],
64+
});
65+
66+
const style = {
67+
...props.style,
68+
transform: CSS.Transform.toString(transform),
69+
transition,
70+
cursor: 'move',
71+
...(isDragging ? { zIndex: 9999 } : {}),
72+
};
73+
74+
return (
75+
<tr {...props} ref={setNodeRef} style={style} {...attributes} {...listeners}>
76+
{children}
77+
</tr>
78+
);
79+
};
80+
81+
const SearchEngineManager: React.FC = () => {
82+
const [engines, setEngines] = useState<SearchEngine[]>(defaultEngines);
83+
const [isModalVisible, setIsModalVisible] = useState(false);
84+
const [editingEngine, setEditingEngine] = useState<SearchEngine | null>(null);
85+
const [form] = Form.useForm();
86+
87+
const columns = [
88+
{
89+
title: '排序',
90+
dataIndex: 'sort',
91+
width: 30,
92+
render: () => <DragOutlined style={{ cursor: 'move', color: '#999' }} />,
93+
},
94+
{
95+
title: 'Logo',
96+
dataIndex: 'logo',
97+
width: 80,
98+
render: (logo: string) => (
99+
<Image src={logo} alt="logo" width={24} height={24} />
100+
),
101+
},
102+
{
103+
title: '名称',
104+
dataIndex: 'name',
105+
},
106+
{
107+
title: '基础URL',
108+
dataIndex: 'baseUrl',
109+
},
110+
{
111+
title: '查询参��',
112+
dataIndex: 'queryParam',
113+
},
114+
{
115+
title: '操作',
116+
width: 120,
117+
render: (_: any, record: SearchEngine) => (
118+
<Space>
119+
<Button
120+
type="text"
121+
icon={<EditOutlined />}
122+
onClick={() => handleEdit(record)}
123+
/>
124+
<Button
125+
type="text"
126+
danger
127+
icon={<DeleteOutlined />}
128+
onClick={() => handleDelete(record.id)}
129+
/>
130+
</Space>
131+
),
132+
},
133+
];
134+
135+
const handleEdit = (engine: SearchEngine) => {
136+
setEditingEngine(engine);
137+
form.setFieldsValue(engine);
138+
setIsModalVisible(true);
139+
};
140+
141+
const handleDelete = (id: string) => {
142+
setEngines(engines.filter((engine) => engine.id !== id));
143+
message.success('删除成功');
144+
};
145+
146+
const handleAdd = () => {
147+
setEditingEngine(null);
148+
form.resetFields();
149+
setIsModalVisible(true);
150+
};
151+
152+
const handleModalOk = async () => {
153+
try {
154+
const values = await form.validateFields();
155+
if (editingEngine) {
156+
setEngines(
157+
engines.map((engine) =>
158+
engine.id === editingEngine.id ? { ...engine, ...values } : engine
159+
)
160+
);
161+
message.success('修改成功');
162+
} else {
163+
const newEngine = {
164+
...values,
165+
id: Date.now().toString(),
166+
order: engines.length + 1,
167+
};
168+
setEngines([...engines, newEngine]);
169+
message.success('添加成功');
170+
}
171+
setIsModalVisible(false);
172+
} catch (error) {
173+
console.error('Validate Failed:', error);
174+
}
175+
};
176+
177+
const onDragEnd = ({ active, over }: any) => {
178+
if (active.id !== over?.id) {
179+
const activeIndex = engines.findIndex((i) => i.id === active.id);
180+
const overIndex = engines.findIndex((i) => i.id === over?.id);
181+
const newItems = [...engines];
182+
const [reorderedItem] = newItems.splice(activeIndex, 1);
183+
newItems.splice(overIndex, 0, reorderedItem);
184+
185+
const reorderedItems = newItems.map((item, index) => ({
186+
...item,
187+
order: index + 1,
188+
}));
189+
190+
setEngines(reorderedItems);
191+
message.success('排序已更新');
192+
}
193+
};
194+
195+
return (
196+
<div>
197+
<div style={{ marginBottom: 16 }}>
198+
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
199+
添加搜索引擎
200+
</Button>
201+
</div>
202+
203+
<DndContext onDragEnd={onDragEnd}>
204+
<SortableContext
205+
items={engines.map((i) => i.id)}
206+
strategy={verticalListSortingStrategy}
207+
>
208+
<Table
209+
columns={columns}
210+
dataSource={engines}
211+
rowKey="id"
212+
components={{
213+
body: {
214+
row: DraggableRow,
215+
},
216+
}}
217+
/>
218+
</SortableContext>
219+
</DndContext>
220+
221+
<Modal
222+
title={editingEngine ? '编辑搜索引擎' : '添加搜索引擎'}
223+
open={isModalVisible}
224+
onOk={handleModalOk}
225+
onCancel={() => setIsModalVisible(false)}
226+
>
227+
<Form form={form} layout="vertical">
228+
<Form.Item
229+
name="name"
230+
label="名称"
231+
rules={[{ required: true, message: '请输入搜索引擎名称' }]}
232+
>
233+
<Input />
234+
</Form.Item>
235+
<Form.Item
236+
name="baseUrl"
237+
label="基础URL"
238+
rules={[{ required: true, message: '请输入基础URL' }]}
239+
>
240+
<Input />
241+
</Form.Item>
242+
<Form.Item
243+
name="queryParam"
244+
label="查询参数"
245+
rules={[{ required: true, message: '请输入查询参数' }]}
246+
>
247+
<Input />
248+
</Form.Item>
249+
<Form.Item
250+
name="logo"
251+
label="Logo URL"
252+
rules={[{ required: true, message: '请输入Logo URL' }]}
253+
>
254+
<Input />
255+
</Form.Item>
256+
</Form>
257+
</Modal>
258+
</div>
259+
);
260+
};
261+
262+
export default SearchEngineManager;

ui/src/pages/admin/tabs/Tools.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,18 @@ export const Tools: React.FC<ToolsProps> = (props) => {
553553
</Form.Item>
554554
<Form.Item
555555
name="url"
556-
rules={[{ required: true, message: "请填写网址" }]}
556+
rules={[
557+
{ required: true, message: "请填写网址" },
558+
{
559+
pattern: /^(https?:\/\/)/,
560+
message: "网址必须以 http:// 或 https:// 开头"
561+
}
562+
]}
557563
required
558564
label="网址"
559565
labelCol={{ span: 4 }}
560566
>
561-
<Input placeholder="请输入 url" />
567+
<Input placeholder="请输入完整URL(以 http:// 或 https:// 开头)" />
562568
</Form.Item>
563569
<Form.Item name="logo" label="logo 网址" labelCol={{ span: 4 }}>
564570
<Input placeholder="请输入 logo url, 为空则自动获取" />
@@ -579,7 +585,7 @@ export const Tools: React.FC<ToolsProps> = (props) => {
579585
rules={[{ required: true, message: "请填写描述" }]}
580586
name="desc"
581587
required
582-
label="描���"
588+
label="描述"
583589
labelCol={{ span: 4 }}
584590
>
585591
<Input placeholder="请输入描述" />
@@ -652,7 +658,7 @@ export const Tools: React.FC<ToolsProps> = (props) => {
652658
>
653659
<Select
654660
options={getOptions(store?.catelogs || [])}
655-
placeholder="请选择分类"
661+
placeholder="请选���分类"
656662
/>
657663
</Form.Item>
658664
<Form.Item name="desc" required label="描述" labelCol={{ span: 4 }}>

utils/jwt.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package utils
22

33
import (
4-
"fmt"
5-
"math/rand"
4+
"crypto/rand"
5+
"encoding/hex"
66
"net/http"
77
"time"
88

@@ -13,7 +13,12 @@ import (
1313
)
1414

1515
func RandomJWTKey() string {
16-
return fmt.Sprintf("%d", rand.Intn(1000000000000000000))
16+
bytes := make([]byte, 32)
17+
if _, err := rand.Read(bytes); err != nil {
18+
logger.LogError("生成随机密钥失败: %v", err)
19+
return "fallback_secret_key_12345"
20+
}
21+
return hex.EncodeToString(bytes)
1722
}
1823

1924
// JTW 密钥

0 commit comments

Comments
 (0)