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.
Files changed (2) hide show
  1. package/api/index.js +89 -20
  2. 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', config.CORS_ALLOW_ORIGIN || request.headers.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.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
- if (!transporter) {
1407
- await initMailer({ throwErr: true })
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
- const formData = new FormData()
1434
- formData.append('image', base64UrlToReadStream(photo, fileName))
1435
- const uploadResult = await axios.post('https://7bu.top/api/upload', formData, {
1436
- headers: {
1437
- ...formData.getHeaders(),
1438
- token: config.IMAGE_CDN_TOKEN
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twikoo-vercel",
3
- "version": "1.5.2",
3
+ "version": "1.5.5",
4
4
  "description": "A simple comment system based on Tencent CloudBase (tcb).",
5
5
  "author": "imaegoo <hello@imaegoo.com> (https://github.com/imaegoo)",
6
6
  "license": "MIT",