twikoo-func 1.7.19 → 1.7.21

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/index.js CHANGED
@@ -7,7 +7,7 @@
7
7
  const { version: VERSION } = require('./package.json')
8
8
  const tcb = require('@cloudbase/node-sdk') // 云开发 SDK
9
9
  const {
10
- getCheerio,
10
+ getHtmlToText,
11
11
  getDomPurify,
12
12
  getMd5,
13
13
  getSha256,
@@ -63,7 +63,7 @@ const app = tcb.init({ env: tcb.SYMBOL_CURRENT_ENV })
63
63
  const auth = app.auth()
64
64
  const db = app.database()
65
65
  const _ = db.command
66
- const $ = getCheerio()
66
+ const htmlToText = getHtmlToText()
67
67
  const DOMPurify = getDomPurify()
68
68
  const md5 = getMd5()
69
69
  const sha256 = getSha256()
@@ -1026,7 +1026,7 @@ async function getRecentComments (event) {
1026
1026
  mailMd5: getMailMd5(comment),
1027
1027
  link: comment.link,
1028
1028
  comment: comment.comment,
1029
- commentText: $(comment.comment).text(),
1029
+ commentText: htmlToText(comment.comment),
1030
1030
  created: comment.created
1031
1031
  }
1032
1032
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "twikoo-func",
3
- "version": "1.7.19",
3
+ "version": "1.7.21",
4
4
  "description": "A simple comment system.",
5
5
  "author": "imaegoo <hello@imaegoo.com> (https://github.com/imaegoo)",
6
6
  "license": "MIT",
@@ -15,22 +15,19 @@
15
15
  "@xsai/shared": "0.2.2",
16
16
  "@xsai/shared-chat": "0.2.2",
17
17
  "@cap.js/server": "^4.0.5",
18
- "@cloudbase/manager-node": "^3.9.0",
19
18
  "@cloudbase/node-sdk": "^2.5.0",
20
19
  "@imaegoo/node-ip2region": "^2.1.1",
21
20
  "akismet-api": "^5.1.0",
22
21
  "axios": "^1.6.2",
23
- "blueimp-md5": "^2.18.0",
24
22
  "bowser": "^2.11.0",
25
- "cheerio": "1.0.0-rc.5",
26
- "crypto-js": "^4.0.0",
27
- "dompurify": "^2.5.9",
23
+ "dompurify": "^3.4.14",
28
24
  "form-data": "^4.0.0",
29
- "jsdom": "^16.4.0",
25
+ "html-to-text": "^9.0.5",
26
+ "jsdom": "^22.1.0",
30
27
  "marked": "^4.0.12",
31
28
  "nodemailer": "^9.0.5",
32
29
  "pushoo": "latest",
33
- "tencentcloud-sdk-nodejs": "^4.0.65",
30
+ "tencentcloud-sdk-nodejs-tms": "^4.1.293",
34
31
  "xml2js": "^0.6.0"
35
32
  }
36
33
  }
package/utils/index.js CHANGED
@@ -99,7 +99,7 @@ const fn = {
99
99
  ruser: fn.ruser(comment.pid, comments),
100
100
  top: comment.top,
101
101
  isSpam: comment.isSpam,
102
- isOwner: comment.uid === uid,
102
+ isOwner: Boolean(uid && comment.uid === uid),
103
103
  created: comment.created,
104
104
  updated: comment.updated
105
105
  }
@@ -474,7 +474,9 @@ const fn = {
474
474
  if (!comment) {
475
475
  throw new Error('评论不存在')
476
476
  }
477
- if (comment.uid !== uid) {
477
+ // token 的请求不具备任何归属权,必须直接拒绝,
478
+ // 防止 comment.uid 与 uid 同时为 undefined 时误判为本人
479
+ if (!uid || comment.uid !== uid) {
478
480
  throw new Error('只能删除自己的评论')
479
481
  }
480
482
  return comment
package/utils/lib.js CHANGED
@@ -1,21 +1,25 @@
1
+ const crypto = require('crypto')
2
+
1
3
  let customLibs = {}
2
4
 
3
5
  module.exports = {
4
6
  setCustomLibs (libs) {
5
7
  customLibs = libs
6
8
  },
7
- getCheerio () {
8
- const $ = require('cheerio') // jQuery 服务器版
9
- return $
9
+ getHtmlToText () {
10
+ const { compile } = require('html-to-text') // HTML 转纯文本
11
+ return compile({
12
+ wordwrap: false,
13
+ selectors: [
14
+ { selector: 'a', options: { ignoreHref: true } },
15
+ { selector: 'img', format: 'skip' }
16
+ ]
17
+ })
10
18
  },
11
19
  getAkismetClient () {
12
20
  const { AkismetClient } = require('akismet-api') // 反垃圾 API
13
21
  return AkismetClient
14
22
  },
15
- getCryptoJS () {
16
- const CryptoJS = require('crypto-js') // 编解码
17
- return CryptoJS
18
- },
19
23
  getFormData () {
20
24
  const FormData = require('form-data') // 图片上传
21
25
  return FormData
@@ -46,13 +50,13 @@ module.exports = {
46
50
  return marked
47
51
  },
48
52
  getMd5 () {
49
- const md5 = require('blueimp-md5') // MD5 哈希
50
- return md5
53
+ return (message) => {
54
+ return crypto.createHash('md5').update(String(message)).digest('hex')
55
+ }
51
56
  },
52
57
  getSha256 () {
53
- const { SHA256 } = require('crypto-js') // SHA256 哈希
54
58
  return (message) => {
55
- return SHA256(message).toString()
59
+ return crypto.createHash('sha256').update(message == null ? '' : String(message)).digest('hex')
56
60
  }
57
61
  },
58
62
  getNodemailer () {
@@ -64,9 +68,9 @@ module.exports = {
64
68
  const pushoo = require('pushoo').default // 即时消息通知
65
69
  return pushoo
66
70
  },
67
- getTencentcloud () {
68
- const tencentcloud = require('tencentcloud-sdk-nodejs') // 腾讯云 API NODEJS SDK
69
- return tencentcloud
71
+ getTencentcloudTms () {
72
+ const tencentcloudTms = require('tencentcloud-sdk-nodejs-tms') // 腾讯云文本内容安全 SDK
73
+ return tencentcloudTms
70
74
  },
71
75
  getXml2js () {
72
76
  const xml2js = require('xml2js') // XML 解析
package/utils/notify.js CHANGED
@@ -1,10 +1,10 @@
1
1
  const { equalsMail, getAvatar, isValidEmail } = require('.')
2
2
  const {
3
- getCheerio,
3
+ getHtmlToText,
4
4
  getNodemailer,
5
5
  getPushoo
6
6
  } = require('./lib')
7
- const $ = getCheerio()
7
+ const htmlToText = getHtmlToText()
8
8
  const pushoo = getPushoo()
9
9
  const { RES_CODE } = require('./constants')
10
10
  const logger = require('./logger')
@@ -175,7 +175,7 @@ const fn = {
175
175
  const NICK = escapeHtml(comment.nick)
176
176
  const MAIL = escapeHtml(comment.mail)
177
177
  const IP = comment.ip
178
- const COMMENT = $(comment.comment).text()
178
+ const COMMENT = htmlToText(comment.comment)
179
179
  const SITE_URL = config.SITE_URL
180
180
  const POST_URL = escapeHtml(fn.appendHashToUrl(comment.href || SITE_URL + comment.url, comment.id))
181
181
  const subject = config.MAIL_SUBJECT_ADMIN || `${SITE_NAME}有新评论了`
package/utils/spam.js CHANGED
@@ -1,28 +1,26 @@
1
1
  const {
2
2
  getAkismetClient,
3
- getCryptoJS,
4
- getTencentcloud
3
+ getTencentcloudTms
5
4
  } = require('./lib')
6
5
  const {
7
6
  equalsMail
8
7
  } = require('.')
9
8
  const AkismetClient = getAkismetClient()
10
- const CryptoJS = getCryptoJS()
11
9
 
12
10
  const logger = require('./logger')
13
11
 
14
- let tencentcloud
12
+ let tencentcloudTms
15
13
  let generateTextPromise
16
14
 
17
- function getTencentCloud () {
18
- if (!tencentcloud) {
15
+ function getTencentCloudTms () {
16
+ if (!tencentcloudTms) {
19
17
  try {
20
- tencentcloud = getTencentcloud() // 腾讯云 API NODEJS SDK
18
+ tencentcloudTms = getTencentcloudTms()
21
19
  } catch (e) {
22
- logger.warn('加载 "tencentcloud-sdk-nodejs" 失败', e)
20
+ logger.warn('加载 "tencentcloud-sdk-nodejs-tms" 失败', e)
23
21
  }
24
22
  }
25
- return tencentcloud
23
+ return tencentcloudTms
26
24
  }
27
25
 
28
26
  function getGenerateText () {
@@ -185,14 +183,14 @@ const fn = {
185
183
  isSpam = false
186
184
  } else if (config.QCLOUD_SECRET_ID && config.QCLOUD_SECRET_KEY) {
187
185
  // 腾讯云内容安全
188
- const client = new (getTencentCloud().tms.v20201229.Client)({
186
+ const client = new (getTencentCloudTms().tms.v20201229.Client)({
189
187
  credential: { secretId: config.QCLOUD_SECRET_ID, secretKey: config.QCLOUD_SECRET_KEY },
190
188
  region: 'ap-shanghai',
191
189
  profile: { httpProfile: { endpoint: 'tms.tencentcloudapi.com' } }
192
190
  })
193
191
  const textModerationParams = {
194
192
  // 文档: https://cloud.tencent.com/document/api/1124/51860
195
- Content: CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(comment.comment)),
193
+ Content: Buffer.from(comment.comment, 'utf8').toString('base64'),
196
194
  DataId: comment.id,
197
195
  User: { Nickname: comment.nick },
198
196
  Device: { IP: comment.ip }
@@ -204,6 +202,9 @@ const fn = {
204
202
  const checkResult = await client.TextModeration(textModerationParams)
205
203
  logger.log('腾讯云返回结果:', checkResult)
206
204
  isSpam = checkResult.Suggestion !== 'Pass'
205
+ if (isSpam) {
206
+ logger.warn(`腾讯云判定不通过: id="${comment.id}" nick="${comment.nick}" suggestion="${checkResult.Suggestion}" label="${checkResult.Label}" subLabel="${checkResult.SubLabel}"`)
207
+ }
207
208
  } else if (config.AKISMET_KEY) {
208
209
  // Akismet
209
210
  const akismetClient = new AkismetClient({