twikoo-vercel 1.5.2 → 1.5.5
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/api/index.js +89 -20
- package/package.json +1 -1
package/api/index.js
CHANGED
|
@@ -163,7 +163,7 @@ module.exports = async (requestArg, responseArg) => {
|
|
|
163
163
|
function allowCors () {
|
|
164
164
|
if (request.headers.origin) {
|
|
165
165
|
response.setHeader('Access-Control-Allow-Credentials', true)
|
|
166
|
-
response.setHeader('Access-Control-Allow-Origin',
|
|
166
|
+
response.setHeader('Access-Control-Allow-Origin', getAllowedOrigin())
|
|
167
167
|
response.setHeader('Access-Control-Allow-Methods', 'POST')
|
|
168
168
|
response.setHeader(
|
|
169
169
|
'Access-Control-Allow-Headers',
|
|
@@ -172,6 +172,18 @@ function allowCors () {
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
+
function getAllowedOrigin () {
|
|
176
|
+
const localhostRegex = /^https?:\/\/(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d{1,5})?$/
|
|
177
|
+
if (localhostRegex.test(request.headers.origin)) {
|
|
178
|
+
return request.headers.origin
|
|
179
|
+
} else if (config.CORS_ALLOW_ORIGIN) {
|
|
180
|
+
// 许多用户设置安全域名时,喜欢带结尾的 "/",必须处理掉
|
|
181
|
+
return config.CORS_ALLOW_ORIGIN.replace(/\/$/, '')
|
|
182
|
+
} else {
|
|
183
|
+
return request.headers.origin
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
175
187
|
function anonymousSignIn () {
|
|
176
188
|
if (request.body) {
|
|
177
189
|
if (request.body.accessToken) {
|
|
@@ -1133,7 +1145,7 @@ async function parse (comment) {
|
|
|
1133
1145
|
comment: DOMPurify.sanitize(comment.comment, { FORBID_TAGS: ['style'], FORBID_ATTR: ['style'] }),
|
|
1134
1146
|
pid: comment.pid ? comment.pid : comment.rid,
|
|
1135
1147
|
rid: comment.rid,
|
|
1136
|
-
isSpam: isAdminUser ? false : preCheckSpam(comment
|
|
1148
|
+
isSpam: isAdminUser ? false : preCheckSpam(comment),
|
|
1137
1149
|
created: timestamp,
|
|
1138
1150
|
updated: timestamp
|
|
1139
1151
|
}
|
|
@@ -1177,7 +1189,7 @@ async function limitFilter () {
|
|
|
1177
1189
|
}
|
|
1178
1190
|
|
|
1179
1191
|
// 预垃圾评论检测
|
|
1180
|
-
function preCheckSpam (comment) {
|
|
1192
|
+
function preCheckSpam ({ comment, nick }) {
|
|
1181
1193
|
// 长度限制
|
|
1182
1194
|
let limitLength = parseInt(config.LIMIT_LENGTH)
|
|
1183
1195
|
if (Number.isNaN(limitLength)) limitLength = 500
|
|
@@ -1191,7 +1203,7 @@ function preCheckSpam (comment) {
|
|
|
1191
1203
|
} else if (config.FORBIDDEN_WORDS) {
|
|
1192
1204
|
// 违禁词检测
|
|
1193
1205
|
for (const forbiddenWord of config.FORBIDDEN_WORDS.split(',')) {
|
|
1194
|
-
if (comment.indexOf(forbiddenWord.trim()) !== -1) {
|
|
1206
|
+
if (comment.indexOf(forbiddenWord.trim()) !== -1 || nick.indexOf(forbiddenWord.trim()) !== -1) {
|
|
1195
1207
|
console.log('包含违禁词,直接标记为垃圾评论~')
|
|
1196
1208
|
return true
|
|
1197
1209
|
}
|
|
@@ -1403,9 +1415,9 @@ async function emailTest (event) {
|
|
|
1403
1415
|
const isAdminUser = await isAdmin()
|
|
1404
1416
|
if (isAdminUser) {
|
|
1405
1417
|
try {
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
}
|
|
1418
|
+
// 邮件测试前清除 transporter,保证读取的是最新的配置
|
|
1419
|
+
transporter = null
|
|
1420
|
+
await initMailer({ throwErr: true })
|
|
1409
1421
|
const sendResult = await transporter.sendMail({
|
|
1410
1422
|
from: config.SENDER_EMAIL,
|
|
1411
1423
|
to: event.mail || config.BLOGGER_EMAIL || config.SENDER_EMAIL,
|
|
@@ -1427,21 +1439,16 @@ async function uploadImage (event) {
|
|
|
1427
1439
|
const { photo, fileName } = event
|
|
1428
1440
|
const res = {}
|
|
1429
1441
|
try {
|
|
1430
|
-
if (!config.IMAGE_CDN_TOKEN) {
|
|
1442
|
+
if (!config.IMAGE_CDN || !config.IMAGE_CDN_TOKEN) {
|
|
1431
1443
|
throw new Error('未配置图片上传服务')
|
|
1432
1444
|
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
}
|
|
1440
|
-
})
|
|
1441
|
-
if (uploadResult.data.code === 200) {
|
|
1442
|
-
res.data = uploadResult.data.data
|
|
1443
|
-
} else {
|
|
1444
|
-
throw new Error(uploadResult.data.msg)
|
|
1445
|
+
// tip: qcloud 图床走前端上传,其他图床走后端上传
|
|
1446
|
+
if (config.IMAGE_CDN === '7bu') {
|
|
1447
|
+
await uploadImageTo7Bu({ photo, fileName, config, res })
|
|
1448
|
+
} else if (config.IMAGE_CDN === 'smms') {
|
|
1449
|
+
await uploadImageToSmms({ photo, fileName, config, res })
|
|
1450
|
+
} else if (isUrl(config.IMAGE_CDN)) {
|
|
1451
|
+
await uploadImageToLskyPro({ photo, fileName, config, res })
|
|
1445
1452
|
}
|
|
1446
1453
|
} catch (e) {
|
|
1447
1454
|
console.error(e)
|
|
@@ -1451,6 +1458,64 @@ async function uploadImage (event) {
|
|
|
1451
1458
|
return res
|
|
1452
1459
|
}
|
|
1453
1460
|
|
|
1461
|
+
async function uploadImageTo7Bu ({ photo, fileName, config, res }) {
|
|
1462
|
+
// 去不图床旧版本 https://7bu.top
|
|
1463
|
+
// TODO: 2022 年 4 月 30 日后去不图床将会升级新版本,此处逻辑要同步更新
|
|
1464
|
+
const formData = new FormData()
|
|
1465
|
+
formData.append('image', base64UrlToReadStream(photo, fileName))
|
|
1466
|
+
const uploadResult = await axios.post('https://7bu.top/api/upload', formData, {
|
|
1467
|
+
headers: {
|
|
1468
|
+
...formData.getHeaders(),
|
|
1469
|
+
token: config.IMAGE_CDN_TOKEN
|
|
1470
|
+
}
|
|
1471
|
+
})
|
|
1472
|
+
if (uploadResult.data.code === 200) {
|
|
1473
|
+
res.data = uploadResult.data.data
|
|
1474
|
+
} else {
|
|
1475
|
+
throw new Error(uploadResult.data.msg)
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
async function uploadImageToSmms ({ photo, fileName, config, res }) {
|
|
1480
|
+
// SM.MS 图床 https://sm.ms
|
|
1481
|
+
const formData = new FormData()
|
|
1482
|
+
formData.append('smfile', base64UrlToReadStream(photo, fileName))
|
|
1483
|
+
const uploadResult = await axios.post('https://sm.ms/api/v2/upload', formData, {
|
|
1484
|
+
headers: {
|
|
1485
|
+
...formData.getHeaders(),
|
|
1486
|
+
Authorization: config.IMAGE_CDN_TOKEN
|
|
1487
|
+
}
|
|
1488
|
+
})
|
|
1489
|
+
if (uploadResult.data.success) {
|
|
1490
|
+
res.data = uploadResult.data.data
|
|
1491
|
+
} else {
|
|
1492
|
+
throw new Error(uploadResult.data.message)
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
async function uploadImageToLskyPro ({ photo, fileName, config, res }) {
|
|
1497
|
+
// 自定义兰空图床(v2)URL
|
|
1498
|
+
const formData = new FormData()
|
|
1499
|
+
formData.append('file', base64UrlToReadStream(photo, fileName))
|
|
1500
|
+
const url = `${config.IMAGE_CDN}/api/v1/upload`
|
|
1501
|
+
let token = config.IMAGE_CDN_TOKEN
|
|
1502
|
+
if (!token.startsWith('Bearer')) {
|
|
1503
|
+
token = `Bearer ${token}`
|
|
1504
|
+
}
|
|
1505
|
+
const uploadResult = await axios.post(url, formData, {
|
|
1506
|
+
headers: {
|
|
1507
|
+
...formData.getHeaders(),
|
|
1508
|
+
Authorization: token
|
|
1509
|
+
}
|
|
1510
|
+
})
|
|
1511
|
+
if (uploadResult.data.status) {
|
|
1512
|
+
res.data = uploadResult.data.data
|
|
1513
|
+
res.data.url = res.data.links.url
|
|
1514
|
+
} else {
|
|
1515
|
+
throw new Error(uploadResult.data.message)
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1454
1519
|
function base64UrlToReadStream (base64Url, fileName) {
|
|
1455
1520
|
const base64 = base64Url.split(';base64,').pop()
|
|
1456
1521
|
const path = `/tmp/${fileName}`
|
|
@@ -1458,6 +1523,10 @@ function base64UrlToReadStream (base64Url, fileName) {
|
|
|
1458
1523
|
return fs.createReadStream(path)
|
|
1459
1524
|
}
|
|
1460
1525
|
|
|
1526
|
+
function isUrl (s) {
|
|
1527
|
+
return /^http(s)?:\/\//.test(s)
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1461
1530
|
function getAvatar (comment) {
|
|
1462
1531
|
if (comment.avatar) {
|
|
1463
1532
|
return comment.avatar
|
package/package.json
CHANGED