@waline/vercel 1.20.1 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/controller/comment.js +34 -37
- package/src/controller/oauth.js +16 -14
- package/src/controller/user.js +1 -2
- package/src/logic/base.js +33 -0
- package/src/logic/comment.js +72 -18
- package/src/logic/token.js +3 -1
- package/src/logic/user.js +3 -1
- package/src/middleware/dashboard.js +1 -0
- package/src/service/storage/mysql.js +4 -5
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@ const { getMarkdownParser } = require('../service/markdown');
|
|
|
6
6
|
const markdownParser = getMarkdownParser();
|
|
7
7
|
|
|
8
8
|
async function formatCmt(
|
|
9
|
-
{ ua,
|
|
9
|
+
{ ua, ip, ...comment },
|
|
10
10
|
users = [],
|
|
11
11
|
{ avatarProxy },
|
|
12
12
|
loginUser
|
|
@@ -20,7 +20,7 @@ async function formatCmt(
|
|
|
20
20
|
comment.os = [ua.os.name, ua.os.version].filter((v) => v).join(' ');
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const user = users.find(({ objectId }) => user_id === objectId);
|
|
23
|
+
const user = users.find(({ objectId }) => comment.user_id === objectId);
|
|
24
24
|
|
|
25
25
|
if (!think.isEmpty(user)) {
|
|
26
26
|
comment.nick = user.display_name;
|
|
@@ -42,10 +42,12 @@ async function formatCmt(
|
|
|
42
42
|
|
|
43
43
|
const isAdmin = loginUser && loginUser.type === 'administrator';
|
|
44
44
|
|
|
45
|
+
if (loginUser) {
|
|
46
|
+
comment.orig = comment.comment;
|
|
47
|
+
}
|
|
45
48
|
if (!isAdmin) {
|
|
46
49
|
delete comment.mail;
|
|
47
50
|
} else {
|
|
48
|
-
comment.orig = comment.comment;
|
|
49
51
|
comment.ip = ip;
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -592,7 +594,7 @@ module.exports = class extends BaseRest {
|
|
|
592
594
|
if (parentComment.user_id) {
|
|
593
595
|
parentUser = await this.service(
|
|
594
596
|
`storage/${this.config('storage')}`,
|
|
595
|
-
'
|
|
597
|
+
'Users'
|
|
596
598
|
).select({
|
|
597
599
|
objectId: parentComment.user_id,
|
|
598
600
|
});
|
|
@@ -642,26 +644,21 @@ module.exports = class extends BaseRest {
|
|
|
642
644
|
|
|
643
645
|
async putAction() {
|
|
644
646
|
const { userInfo } = this.ctx.state;
|
|
645
|
-
|
|
647
|
+
const isAdmin = userInfo.type === 'administrator';
|
|
648
|
+
let data = isAdmin ? this.post() : this.post('comment,like');
|
|
646
649
|
let oldData = await this.modelInstance.select({ objectId: this.id });
|
|
647
650
|
|
|
648
|
-
if (think.isEmpty(oldData)) {
|
|
651
|
+
if (think.isEmpty(oldData) || think.isEmpty(data)) {
|
|
649
652
|
return this.success();
|
|
650
653
|
}
|
|
651
654
|
|
|
652
655
|
oldData = oldData[0];
|
|
653
|
-
if (think.
|
|
654
|
-
if (!think.isBoolean(data.like)) {
|
|
655
|
-
return this.success();
|
|
656
|
-
}
|
|
657
|
-
|
|
656
|
+
if (think.isBoolean(data.like)) {
|
|
658
657
|
const likeIncMax = this.config('LIKE_INC_MAX') || 1;
|
|
659
658
|
|
|
660
|
-
data =
|
|
661
|
-
like
|
|
662
|
-
|
|
663
|
-
(data.like ? Math.ceil(Math.random() * likeIncMax) : -1),
|
|
664
|
-
};
|
|
659
|
+
data.like =
|
|
660
|
+
(Number(oldData.like) || 0) +
|
|
661
|
+
(data.like ? Math.ceil(Math.random() * likeIncMax) : -1);
|
|
665
662
|
}
|
|
666
663
|
|
|
667
664
|
const preUpdateResp = await this.hook('preUpdate', {
|
|
@@ -677,23 +674,29 @@ module.exports = class extends BaseRest {
|
|
|
677
674
|
objectId: this.id,
|
|
678
675
|
});
|
|
679
676
|
|
|
677
|
+
let cmtUser;
|
|
678
|
+
|
|
679
|
+
if (!think.isEmpty(newData) && newData[0].user_id) {
|
|
680
|
+
cmtUser = await this.service(
|
|
681
|
+
`storage/${this.config('storage')}`,
|
|
682
|
+
'Users'
|
|
683
|
+
).select({
|
|
684
|
+
objectId: newData[0].user_id,
|
|
685
|
+
});
|
|
686
|
+
cmtUser = cmtUser[0];
|
|
687
|
+
}
|
|
688
|
+
const cmtReturn = await formatCmt(
|
|
689
|
+
newData[0],
|
|
690
|
+
cmtUser ? [cmtUser] : [],
|
|
691
|
+
this.config(),
|
|
692
|
+
userInfo
|
|
693
|
+
);
|
|
694
|
+
|
|
680
695
|
if (
|
|
681
696
|
oldData.status === 'waiting' &&
|
|
682
697
|
data.status === 'approved' &&
|
|
683
698
|
oldData.pid
|
|
684
699
|
) {
|
|
685
|
-
let cmtUser;
|
|
686
|
-
|
|
687
|
-
if (newData.user_id) {
|
|
688
|
-
cmtUser = await this.service(
|
|
689
|
-
`storage/${this.config('storage')}`,
|
|
690
|
-
'User'
|
|
691
|
-
).select({
|
|
692
|
-
objectId: newData.user_id,
|
|
693
|
-
});
|
|
694
|
-
cmtUser = cmtUser[0];
|
|
695
|
-
}
|
|
696
|
-
|
|
697
700
|
let pComment = await this.modelInstance.select({
|
|
698
701
|
objectId: oldData.pid,
|
|
699
702
|
});
|
|
@@ -705,7 +708,7 @@ module.exports = class extends BaseRest {
|
|
|
705
708
|
if (pComment.user_id) {
|
|
706
709
|
pUser = await this.service(
|
|
707
710
|
`storage/${this.config('storage')}`,
|
|
708
|
-
'
|
|
711
|
+
'Users'
|
|
709
712
|
).select({
|
|
710
713
|
objectId: pComment.user_id,
|
|
711
714
|
});
|
|
@@ -713,12 +716,6 @@ module.exports = class extends BaseRest {
|
|
|
713
716
|
}
|
|
714
717
|
|
|
715
718
|
const notify = this.service('notify');
|
|
716
|
-
const cmtReturn = await formatCmt(
|
|
717
|
-
newData,
|
|
718
|
-
cmtUser ? [cmtUser] : [],
|
|
719
|
-
this.config(),
|
|
720
|
-
userInfo
|
|
721
|
-
);
|
|
722
719
|
const pcmtReturn = await formatCmt(
|
|
723
720
|
pComment,
|
|
724
721
|
pUser ? [pUser] : [],
|
|
@@ -727,7 +724,7 @@ module.exports = class extends BaseRest {
|
|
|
727
724
|
);
|
|
728
725
|
|
|
729
726
|
await notify.run(
|
|
730
|
-
{ ...cmtReturn, mail: newData.mail },
|
|
727
|
+
{ ...cmtReturn, mail: newData[0].mail },
|
|
731
728
|
{ ...pcmtReturn, mail: pComment.mail },
|
|
732
729
|
true
|
|
733
730
|
);
|
|
@@ -735,7 +732,7 @@ module.exports = class extends BaseRest {
|
|
|
735
732
|
|
|
736
733
|
await this.hook('postUpdate', data);
|
|
737
734
|
|
|
738
|
-
return this.success();
|
|
735
|
+
return this.success(cmtReturn);
|
|
739
736
|
}
|
|
740
737
|
|
|
741
738
|
async deleteAction() {
|
package/src/controller/oauth.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const jwt = require('jsonwebtoken');
|
|
2
2
|
const fetch = require('node-fetch');
|
|
3
3
|
const { PasswordHash } = require('phpass');
|
|
4
|
-
const qs = require('querystring');
|
|
5
4
|
|
|
6
5
|
module.exports = class extends think.Controller {
|
|
7
6
|
constructor(ctx) {
|
|
@@ -21,16 +20,16 @@ module.exports = class extends think.Controller {
|
|
|
21
20
|
|
|
22
21
|
if (!hasCode) {
|
|
23
22
|
const { serverURL } = this.ctx;
|
|
24
|
-
const redirectUrl = `${serverURL}/oauth?${
|
|
23
|
+
const redirectUrl = `${serverURL}/oauth?${new URLSearchParams({
|
|
25
24
|
redirect,
|
|
26
25
|
type,
|
|
27
|
-
})}`;
|
|
26
|
+
}).toString()}`;
|
|
28
27
|
|
|
29
28
|
return this.redirect(
|
|
30
|
-
`${oauthUrl}/${type}?${
|
|
29
|
+
`${oauthUrl}/${type}?${new URLSearchParams({
|
|
31
30
|
redirect: redirectUrl,
|
|
32
31
|
state: this.ctx.state.token,
|
|
33
|
-
})}`
|
|
32
|
+
}).toString()}`
|
|
34
33
|
);
|
|
35
34
|
}
|
|
36
35
|
|
|
@@ -41,23 +40,26 @@ module.exports = class extends think.Controller {
|
|
|
41
40
|
|
|
42
41
|
if (type === 'facebook') {
|
|
43
42
|
const { serverURL } = this.ctx;
|
|
44
|
-
const redirectUrl = `${serverURL}/oauth?${
|
|
43
|
+
const redirectUrl = `${serverURL}/oauth?${new URLSearchParams({
|
|
45
44
|
redirect,
|
|
46
45
|
type,
|
|
47
|
-
})}`;
|
|
46
|
+
}).toString()}`;
|
|
48
47
|
|
|
49
|
-
params.state =
|
|
48
|
+
params.state = new URLSearchParams({
|
|
50
49
|
redirect: redirectUrl,
|
|
51
50
|
state: this.ctx.state.token || '',
|
|
52
51
|
});
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
const user = await fetch(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
54
|
+
const user = await fetch(
|
|
55
|
+
`${oauthUrl}/${type}?${new URLSearchParams(params).toString()}`,
|
|
56
|
+
{
|
|
57
|
+
method: 'GET',
|
|
58
|
+
headers: {
|
|
59
|
+
'user-agent': '@waline',
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
).then((resp) => resp.json());
|
|
61
63
|
|
|
62
64
|
if (!user || !user.id) {
|
|
63
65
|
return this.fail(user);
|
package/src/controller/user.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const qs = require('querystring');
|
|
2
1
|
const { PasswordHash } = require('phpass');
|
|
3
2
|
const BaseRest = require('./rest');
|
|
4
3
|
|
|
@@ -82,7 +81,7 @@ module.exports = class extends BaseRest {
|
|
|
82
81
|
const apiUrl =
|
|
83
82
|
this.ctx.serverURL +
|
|
84
83
|
'/verification?' +
|
|
85
|
-
|
|
84
|
+
new URLSearchParams({ token, email: data.email }).toString();
|
|
86
85
|
|
|
87
86
|
await notify.transporter.sendMail({
|
|
88
87
|
from:
|
package/src/logic/base.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const qs = require('querystring');
|
|
3
|
+
const fetch = require('node-fetch');
|
|
2
4
|
const jwt = require('jsonwebtoken');
|
|
3
5
|
const helper = require('think-helper');
|
|
4
6
|
|
|
@@ -122,4 +124,35 @@ module.exports = class extends think.Logic {
|
|
|
122
124
|
|
|
123
125
|
return '';
|
|
124
126
|
}
|
|
127
|
+
|
|
128
|
+
async useCaptchaCheck() {
|
|
129
|
+
const { RECAPTCHA_V3_SECRET } = process.env;
|
|
130
|
+
|
|
131
|
+
if (!RECAPTCHA_V3_SECRET) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const { recaptchaV3 } = this.post();
|
|
135
|
+
|
|
136
|
+
if (!recaptchaV3) {
|
|
137
|
+
return this.ctx.throw(403);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const query = qs.stringify({
|
|
141
|
+
secret: RECAPTCHA_V3_SECRET,
|
|
142
|
+
response: recaptchaV3,
|
|
143
|
+
remoteip: this.ctx.ip,
|
|
144
|
+
});
|
|
145
|
+
const recaptchaV3Result = await fetch(
|
|
146
|
+
`https://recaptcha.net/recaptcha/api/siteverify?${query}`
|
|
147
|
+
).then((resp) => resp.json());
|
|
148
|
+
|
|
149
|
+
if (!recaptchaV3Result.success) {
|
|
150
|
+
think.logger.debug(
|
|
151
|
+
'RecaptchaV3 Result:',
|
|
152
|
+
JSON.stringify(recaptchaV3Result, null, '\t')
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
return this.ctx.throw(403);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
125
158
|
};
|
package/src/logic/comment.js
CHANGED
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
const Base = require('./base');
|
|
2
2
|
|
|
3
3
|
module.exports = class extends Base {
|
|
4
|
-
|
|
5
|
-
await super.__before();
|
|
6
|
-
|
|
7
|
-
const { type, path } = this.get();
|
|
8
|
-
const { like } = this.post();
|
|
9
|
-
const isAllowedGet = this.isGet && (type !== 'list' || path);
|
|
10
|
-
const isAllowedPut = this.ctx.isMethod('PUT') && think.isBoolean(like);
|
|
11
|
-
|
|
12
|
-
if (this.isPost || isAllowedGet || isAllowedPut) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
|
|
4
|
+
checkAdmin() {
|
|
16
5
|
const { userInfo } = this.ctx.state;
|
|
17
6
|
|
|
18
7
|
if (think.isEmpty(userInfo)) {
|
|
@@ -116,7 +105,12 @@ module.exports = class extends Base {
|
|
|
116
105
|
* @apiSuccess (200) {String} response.type comment login user type
|
|
117
106
|
*/
|
|
118
107
|
getAction() {
|
|
119
|
-
const { type } = this.get();
|
|
108
|
+
const { type, path } = this.get();
|
|
109
|
+
const isAllowedGet = type !== 'list' || path;
|
|
110
|
+
|
|
111
|
+
if (!isAllowedGet) {
|
|
112
|
+
this.checkAdmin();
|
|
113
|
+
}
|
|
120
114
|
|
|
121
115
|
switch (type) {
|
|
122
116
|
case 'recent':
|
|
@@ -206,13 +200,19 @@ module.exports = class extends Base {
|
|
|
206
200
|
* @apiSuccess (200) {String} data.avatar comment user avatar
|
|
207
201
|
* @apiSuccess (200) {String} data.type comment login user type
|
|
208
202
|
*/
|
|
209
|
-
postAction() {
|
|
203
|
+
async postAction() {
|
|
210
204
|
const { LOGIN } = process.env;
|
|
211
205
|
const { userInfo } = this.ctx.state;
|
|
212
206
|
|
|
213
|
-
if (
|
|
207
|
+
if (!think.isEmpty(userInfo)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (LOGIN === 'force') {
|
|
214
212
|
return this.ctx.throw(401);
|
|
215
213
|
}
|
|
214
|
+
|
|
215
|
+
return this.useCaptchaCheck();
|
|
216
216
|
}
|
|
217
217
|
|
|
218
218
|
/**
|
|
@@ -230,17 +230,46 @@ module.exports = class extends Base {
|
|
|
230
230
|
* @apiSuccess (200) {Number} errno 0
|
|
231
231
|
* @apiSuccess (200) {String} errmsg return error message if error
|
|
232
232
|
*/
|
|
233
|
-
putAction() {
|
|
233
|
+
async putAction() {
|
|
234
234
|
const { userInfo } = this.ctx.state;
|
|
235
|
+
const { like } = this.post();
|
|
235
236
|
|
|
236
|
-
|
|
237
|
+
// 1. like
|
|
238
|
+
if (think.isEmpty(userInfo) && think.isBoolean(like)) {
|
|
237
239
|
this.rules = {
|
|
238
240
|
like: {
|
|
239
241
|
required: true,
|
|
240
242
|
boolean: true,
|
|
241
243
|
},
|
|
242
244
|
};
|
|
245
|
+
|
|
246
|
+
return;
|
|
243
247
|
}
|
|
248
|
+
|
|
249
|
+
if (think.isEmpty(userInfo)) {
|
|
250
|
+
return this.ctx.throw(401);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 2. administrator
|
|
254
|
+
if (userInfo.type === 'administrator') {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// 3. comment author modify comment content
|
|
259
|
+
const modelInstance = this.service(
|
|
260
|
+
`storage/${this.config('storage')}`,
|
|
261
|
+
'Comment'
|
|
262
|
+
);
|
|
263
|
+
const commentData = await modelInstance.select({
|
|
264
|
+
user_id: userInfo.objectId,
|
|
265
|
+
objectId: this.id,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
if (!think.isEmpty(commentData)) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return this.ctx.throw(403);
|
|
244
273
|
}
|
|
245
274
|
|
|
246
275
|
/**
|
|
@@ -251,5 +280,30 @@ module.exports = class extends Base {
|
|
|
251
280
|
* @apiSuccess (200) {Number} errno 0
|
|
252
281
|
* @apiSuccess (200) {String} errmsg return error message if error
|
|
253
282
|
*/
|
|
254
|
-
deleteAction() {
|
|
283
|
+
async deleteAction() {
|
|
284
|
+
const { userInfo } = this.ctx.state;
|
|
285
|
+
|
|
286
|
+
if (think.isEmpty(userInfo)) {
|
|
287
|
+
return this.ctx.throw(401);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (userInfo.type === 'administrator') {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const modelInstance = this.service(
|
|
295
|
+
`storage/${this.config('storage')}`,
|
|
296
|
+
'Comment'
|
|
297
|
+
);
|
|
298
|
+
const commentData = await modelInstance.select({
|
|
299
|
+
user_id: userInfo.objectId,
|
|
300
|
+
objectId: this.id,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
if (!think.isEmpty(commentData)) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return this.ctx.throw(403);
|
|
308
|
+
}
|
|
255
309
|
};
|
package/src/logic/token.js
CHANGED
|
@@ -32,7 +32,9 @@ module.exports = class extends Base {
|
|
|
32
32
|
* @apiSuccess (200) {Number} errno 0
|
|
33
33
|
* @apiSuccess (200) {String} errmsg return error message if error
|
|
34
34
|
*/
|
|
35
|
-
postAction() {
|
|
35
|
+
postAction() {
|
|
36
|
+
return this.useCaptchaCheck();
|
|
37
|
+
}
|
|
36
38
|
|
|
37
39
|
/**
|
|
38
40
|
* @api {DELETE} /token user logout
|
package/src/logic/user.js
CHANGED
|
@@ -33,7 +33,9 @@ module.exports = class extends Base {
|
|
|
33
33
|
* @apiSuccess (200) {Number} errno 0
|
|
34
34
|
* @apiSuccess (200) {String} errmsg return error message if error
|
|
35
35
|
*/
|
|
36
|
-
postAction() {
|
|
36
|
+
postAction() {
|
|
37
|
+
return this.useCaptchaCheck();
|
|
38
|
+
}
|
|
37
39
|
|
|
38
40
|
/**
|
|
39
41
|
* @api {PUT} /user update user profile
|
|
@@ -12,6 +12,7 @@ module.exports = function () {
|
|
|
12
12
|
<script>
|
|
13
13
|
window.SITE_URL = ${JSON.stringify(process.env.SITE_URL)};
|
|
14
14
|
window.SITE_NAME = ${JSON.stringify(process.env.SITE_NAME)};
|
|
15
|
+
window.recaptchaV3Key = ${JSON.stringify(process.env.RECAPTCHA_V3_KEY)};
|
|
15
16
|
</script>
|
|
16
17
|
<script src="${
|
|
17
18
|
process.env.WALINE_ADMIN_MODULE_ASSET_URL || '//unpkg.com/@waline/admin'
|
|
@@ -67,7 +67,7 @@ module.exports = class extends Base {
|
|
|
67
67
|
return instance.count();
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
instance.field([...group, 'COUNT(*) as count']);
|
|
70
|
+
instance.field([...group, 'COUNT(*) as count'].join(','));
|
|
71
71
|
instance.group(group);
|
|
72
72
|
|
|
73
73
|
return instance.select();
|
|
@@ -79,10 +79,9 @@ module.exports = class extends Base {
|
|
|
79
79
|
delete data.objectId;
|
|
80
80
|
}
|
|
81
81
|
const date = new Date();
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (!data.updatedAt)
|
|
85
|
-
data.updatedAt = date;
|
|
82
|
+
|
|
83
|
+
if (!data.createdAt) data.createdAt = date;
|
|
84
|
+
if (!data.updatedAt) data.updatedAt = date;
|
|
86
85
|
|
|
87
86
|
const instance = this.model(this.tableName);
|
|
88
87
|
const id = await instance.add(data);
|