forked from syzoj/syzoj
-
Notifications
You must be signed in to change notification settings - Fork 1
/
1.patch
144 lines (137 loc) · 4.93 KB
/
1.patch
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
141
142
143
144
diff --git a/config-example.json b/config-example.json
index dc07a1e..6206e1c 100644
--- a/config-example.json
+++ b/config-example.json
@@ -125,5 +125,6 @@
},
"no_cdn": false,
"username_regex": "^[a-zA-Z0-9\\-\\_]+$",
- "submissions_page_fast_pagination": false
+ "submissions_page_fast_pagination": false,
+ "site_for_download": ""
}
diff --git a/modules/api.js b/modules/api.js
index 6abaaf4..8731053 100644
--- a/modules/api.js
+++ b/modules/api.js
@@ -42,8 +42,7 @@ app.post('/api/forget', async (req, res) => {
expiresIn: '12h'
});
- const currentProto = req.get("X-Forwarded-Proto") || req.protocol;
- const vurl = currentProto + '://' + req.get('host') + syzoj.utils.makeUrl(['api', 'forget_confirm'], { token: token });
+ const vurl = syzoj.utils.getCurrentLocation(req, true) + syzoj.utils.makeUrl(['api', 'forget_confirm'], { token: token });
try {
await Email.send(user.email,
`${user.username} 的 ${syzoj.config.title} 密码重置邮件`,
@@ -93,8 +92,7 @@ app.post('/api/sign_up', async (req, res) => {
expiresIn: '2d'
});
- const currentProto = req.get("X-Forwarded-Proto") || req.protocol;
- const vurl = currentProto + '://' + req.get('host') + syzoj.utils.makeUrl(['api', 'sign_up_confirm'], { token: token });
+ const vurl = syzoj.utils.getCurrentLocation(req, true) + syzoj.utils.makeUrl(['api', 'sign_up_confirm'], { token: token });
try {
await Email.send(req.body.email,
`${req.body.username} 的 ${syzoj.config.title} 注册验证邮件`,
diff --git a/modules/api_v2.js b/modules/api_v2.js
index 2e88299..e5c6a26 100644
--- a/modules/api_v2.js
+++ b/modules/api_v2.js
@@ -1,3 +1,5 @@
+const jwt = require('jsonwebtoken');
+
app.get('/api/v2/search/users/:keyword*?', async (req, res) => {
try {
let User = syzoj.model('user');
@@ -104,3 +106,29 @@ app.apiRouter.post('/api/v2/markdown', async (req, res) => {
res.send(e);
}
});
+
+function verifyJWT(token) {
+ try {
+ jwt.verify(token, syzoj.config.session_secret);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
+
+app.apiRouter.get('/api/v2/download/:token', async (req, res) => {
+ try {
+ const token = req.params.token, data = jwt.decode(token);
+ if (!data) throw new ErrorMessage("无效的令牌。");
+ if (verifyJWT(token)) {
+ res.download(data.filename, data.sendName);
+ } else {
+ res.redirect(data.originUrl);
+ }
+ } catch (e) {
+ syzoj.log(e);
+ res.render('error', {
+ err: e
+ });
+ }
+})
diff --git a/modules/problem.js b/modules/problem.js
index 751b89f..b7ae601 100644
--- a/modules/problem.js
+++ b/modules/problem.js
@@ -7,6 +7,7 @@ let Article = syzoj.model('article');
const randomstring = require('randomstring');
const fs = require('fs-extra');
+const jwt = require('jsonwebtoken');
let Judger = syzoj.lib('judger');
let CodeFormatter = syzoj.lib('code_formatter');
@@ -816,6 +817,20 @@ app.post('/problem/:id/testdata/delete/:filename', async (req, res) => {
}
});
+function downloadOrRedirect(req, res, filename, sendName) {
+ if (syzoj.config.site_for_download) {
+ res.redirect(syzoj.config.site_for_download + syzoj.utils.makeUrl(['api', 'v2', 'download', jwt.sign({
+ filename: filename,
+ sendName: sendName,
+ originUrl: syzoj.utils.getCurrentLocation(req)
+ }, syzoj.config.session_secret, {
+ expiresIn: '2m'
+ })]));
+ } else {
+ res.download(filename, sendName);
+ }
+}
+
app.get('/problem/:id/testdata/download/:filename?', async (req, res) => {
try {
let id = parseInt(req.params.id);
@@ -833,7 +848,8 @@ app.get('/problem/:id/testdata/download/:filename?', async (req, res) => {
let path = require('path');
let filename = req.params.filename ? path.join(problem.getTestdataPath(), req.params.filename) : (problem.getTestdataArchivePath());
if (!await syzoj.utils.isFile(filename)) throw new ErrorMessage('文件不存在。');
- res.download(filename, path.basename(filename));
+
+ downloadOrRedirect(req, res, filename, path.basename(filename));
} catch (e) {
syzoj.log(e);
res.status(404);
@@ -866,7 +882,7 @@ app.get('/problem/:id/download/additional_file', async (req, res) => {
if (!problem.additional_file) throw new ErrorMessage('无附加文件。');
- res.download(problem.additional_file.getPath(), `additional_file_${id}.zip`);
+ downloadOrRedirect(req, res, problem.additional_file.getPath(), `additional_file_${id}.zip`);
} catch (e) {
syzoj.log(e);
res.status(404);
diff --git a/utility.js b/utility.js
index b5c4f10..44f8a2a 100644
--- a/utility.js
+++ b/utility.js
@@ -320,5 +320,11 @@ module.exports = {
}
attempt();
});
+ },
+ getCurrentLocation(req, hostOnly) {
+ const currentProto = req.get("X-Forwarded-Proto") || req.protocol,
+ host = currentProto + '://' + req.get('host');
+ if (hostOnly) return host;
+ else return host + req.originalUrl;
}
};