@waline/vercel 1.30.1 → 1.30.2

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 (59) hide show
  1. package/package.json +9 -6
  2. package/src/controller/db.js +18 -0
  3. package/dist/404.html +0 -39
  4. package/dist/500.html +0 -275
  5. package/dist/index.js +0 -58521
  6. package/dist/package.json +0 -55
  7. package/dist/src/config/adapter.js +0 -170
  8. package/dist/src/config/config.js +0 -134
  9. package/dist/src/config/extend.js +0 -38
  10. package/dist/src/config/middleware.js +0 -67
  11. package/dist/src/config/router.js +0 -1
  12. package/dist/src/controller/article.js +0 -88
  13. package/dist/src/controller/comment.js +0 -736
  14. package/dist/src/controller/db.js +0 -71
  15. package/dist/src/controller/index.js +0 -36
  16. package/dist/src/controller/oauth.js +0 -136
  17. package/dist/src/controller/rest.js +0 -60
  18. package/dist/src/controller/token/2fa.js +0 -67
  19. package/dist/src/controller/token.js +0 -76
  20. package/dist/src/controller/user/password.js +0 -53
  21. package/dist/src/controller/user.js +0 -290
  22. package/dist/src/controller/verification.js +0 -35
  23. package/dist/src/extend/controller.js +0 -26
  24. package/dist/src/extend/think.js +0 -104
  25. package/dist/src/locales/en.json +0 -19
  26. package/dist/src/locales/index.js +0 -12
  27. package/dist/src/locales/zh-CN.json +0 -19
  28. package/dist/src/locales/zh-TW.json +0 -19
  29. package/dist/src/logic/article.js +0 -27
  30. package/dist/src/logic/base.js +0 -165
  31. package/dist/src/logic/comment.js +0 -317
  32. package/dist/src/logic/db.js +0 -81
  33. package/dist/src/logic/oauth.js +0 -10
  34. package/dist/src/logic/token/2fa.js +0 -28
  35. package/dist/src/logic/token.js +0 -53
  36. package/dist/src/logic/user/password.js +0 -11
  37. package/dist/src/logic/user.js +0 -117
  38. package/dist/src/middleware/dashboard.js +0 -23
  39. package/dist/src/middleware/version.js +0 -6
  40. package/dist/src/service/akismet.js +0 -42
  41. package/dist/src/service/avatar.js +0 -36
  42. package/dist/src/service/markdown/highlight.js +0 -32
  43. package/dist/src/service/markdown/index.js +0 -64
  44. package/dist/src/service/markdown/katex.js +0 -50
  45. package/dist/src/service/markdown/mathCommon.js +0 -156
  46. package/dist/src/service/markdown/mathjax.js +0 -78
  47. package/dist/src/service/markdown/utils.js +0 -11
  48. package/dist/src/service/markdown/xss.js +0 -44
  49. package/dist/src/service/notify.js +0 -538
  50. package/dist/src/service/storage/base.js +0 -31
  51. package/dist/src/service/storage/cloudbase.js +0 -222
  52. package/dist/src/service/storage/deta.js +0 -309
  53. package/dist/src/service/storage/github.js +0 -379
  54. package/dist/src/service/storage/leancloud.js +0 -432
  55. package/dist/src/service/storage/mongodb.js +0 -180
  56. package/dist/src/service/storage/mysql.js +0 -123
  57. package/dist/src/service/storage/postgresql.js +0 -84
  58. package/dist/src/service/storage/sqlite.js +0 -11
  59. package/dist/src/service/storage/tidb.js +0 -3
@@ -1,538 +0,0 @@
1
- const crypto = require('crypto');
2
-
3
- const FormData = require('form-data');
4
- const fetch = require('node-fetch');
5
- const nodemailer = require('nodemailer');
6
- const nunjucks = require('nunjucks');
7
-
8
- module.exports = class extends think.Service {
9
- constructor(ctx) {
10
- super(ctx);
11
-
12
- this.ctx = ctx;
13
- const {
14
- SMTP_USER,
15
- SMTP_PASS,
16
- SMTP_HOST,
17
- SMTP_PORT,
18
- SMTP_SECURE,
19
- SMTP_SERVICE,
20
- } = process.env;
21
-
22
- if (SMTP_HOST || SMTP_SERVICE) {
23
- const config = {
24
- auth: { user: SMTP_USER, pass: SMTP_PASS },
25
- };
26
-
27
- if (SMTP_SERVICE) {
28
- config.service = SMTP_SERVICE;
29
- } else {
30
- config.host = SMTP_HOST;
31
- config.port = parseInt(SMTP_PORT);
32
- config.secure = SMTP_SECURE && SMTP_SECURE !== 'false';
33
- }
34
- this.transporter = nodemailer.createTransport(config);
35
- }
36
- }
37
-
38
- async sleep(second) {
39
- return new Promise((resolve) => setTimeout(resolve, second * 1000));
40
- }
41
-
42
- async mail({ to, title, content }, self, parent) {
43
- if (!this.transporter) {
44
- return;
45
- }
46
-
47
- const { SITE_NAME, SITE_URL, SMTP_USER, SENDER_EMAIL, SENDER_NAME } =
48
- process.env;
49
- const data = {
50
- self,
51
- parent,
52
- site: {
53
- name: SITE_NAME,
54
- url: SITE_URL,
55
- postUrl: SITE_URL + self.url + '#' + self.objectId,
56
- },
57
- };
58
-
59
- title = this.ctx.locale(title, data);
60
- content = this.ctx.locale(content, data);
61
-
62
- return this.transporter.sendMail({
63
- from:
64
- SENDER_EMAIL && SENDER_NAME
65
- ? `"${SENDER_NAME}" <${SENDER_EMAIL}>`
66
- : SMTP_USER,
67
- to,
68
- subject: title,
69
- html: content,
70
- });
71
- }
72
-
73
- async wechat({ title, content }, self, parent) {
74
- const { SC_KEY, SITE_NAME, SITE_URL } = process.env;
75
-
76
- if (!SC_KEY) {
77
- return false;
78
- }
79
-
80
- const data = {
81
- self,
82
- parent,
83
- site: {
84
- name: SITE_NAME,
85
- url: SITE_URL,
86
- postUrl: SITE_URL + self.url + '#' + self.objectId,
87
- },
88
- };
89
-
90
- title = this.ctx.locale(title, data);
91
- content = this.ctx.locale(content, data);
92
-
93
- const form = new FormData();
94
-
95
- form.append('text', title);
96
- form.append('desp', content);
97
-
98
- return fetch(`https://sctapi.ftqq.com/${SC_KEY}.send`, {
99
- method: 'POST',
100
- headers: form.getHeaders(),
101
- body: form,
102
- }).then((resp) => resp.json());
103
- }
104
-
105
- async qywxAmWechat({ title, content }, self, parent) {
106
- const { QYWX_AM, SITE_NAME, SITE_URL } = process.env;
107
-
108
- if (!QYWX_AM) {
109
- return false;
110
- }
111
-
112
- const QYWX_AM_AY = QYWX_AM.split(',');
113
- const comment = self.comment
114
- .replace(/<a href="(.*?)">(.*?)<\/a>/g, '\n[$2] $1\n')
115
- .replace(/<[^>]+>/g, '');
116
- const postName = self.url;
117
-
118
- const data = {
119
- self: {
120
- ...self,
121
- comment,
122
- },
123
- postName,
124
- parent,
125
- site: {
126
- name: SITE_NAME,
127
- url: SITE_URL,
128
- postUrl: SITE_URL + self.url + '#' + self.objectId,
129
- },
130
- };
131
- const contentWechat =
132
- think.config('WXTemplate') ||
133
- `💬 {{site.name|safe}}的文章《{{postName}}》有新评论啦
134
- 【评论者昵称】:{{self.nick}}
135
- 【评论者邮箱】:{{self.mail}}
136
- 【内容】:{{self.comment}}
137
- <a href='{{site.postUrl}}'>查看详情</a>`;
138
-
139
- title = this.ctx.locale(title, data);
140
- const desp = this.ctx.locale(contentWechat, data);
141
-
142
- content = desp.replace(/\n/g, '<br/>');
143
-
144
- const querystring = new URLSearchParams();
145
-
146
- querystring.set('corpid', `${QYWX_AM_AY[0]}`);
147
- querystring.set('corpsecret', `${QYWX_AM_AY[1]}`);
148
-
149
- const { access_token } = await fetch(
150
- `https://qyapi.weixin.qq.com/cgi-bin/gettoken?${querystring.toString()}`,
151
- {
152
- headers: {
153
- 'content-type': 'application/json',
154
- },
155
- }
156
- ).then((resp) => resp.json());
157
-
158
- return fetch(
159
- `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${access_token}`,
160
- {
161
- method: 'POST',
162
- headers: {
163
- 'content-type': 'application/json',
164
- },
165
- body: JSON.stringify({
166
- touser: `${QYWX_AM_AY[2]}`,
167
- agentid: `${QYWX_AM_AY[3]}`,
168
- msgtype: 'mpnews',
169
- mpnews: {
170
- articles: [
171
- {
172
- title,
173
- thumb_media_id: `${QYWX_AM_AY[4]}`,
174
- author: `Waline Comment`,
175
- content_source_url: `${data.site.postUrl}`,
176
- content: `${content}`,
177
- digest: `${desp}`,
178
- },
179
- ],
180
- },
181
- }),
182
- }
183
- ).then((resp) => resp.json());
184
- }
185
-
186
- async qq(self, parent) {
187
- const { QMSG_KEY, QQ_ID, SITE_NAME, SITE_URL } = process.env;
188
-
189
- if (!QMSG_KEY) {
190
- return false;
191
- }
192
-
193
- const comment = self.comment
194
- .replace(/<a href="(.*?)">(.*?)<\/a>/g, '')
195
- .replace(/<[^>]+>/g, '');
196
-
197
- const data = {
198
- self: {
199
- ...self,
200
- comment,
201
- },
202
- parent,
203
- site: {
204
- name: SITE_NAME,
205
- url: SITE_URL,
206
- postUrl: SITE_URL + self.url + '#' + self.objectId,
207
- },
208
- };
209
-
210
- const contentQQ =
211
- think.config('QQTemplate') ||
212
- `💬 {{site.name|safe}} 有新评论啦
213
- {{self.nick}} 评论道:
214
- {{self.comment}}
215
- 仅供预览评论,请前往上述页面查看完整內容。`;
216
-
217
- const form = new FormData();
218
-
219
- form.append('msg', this.ctx.locale(contentQQ, data));
220
- form.append('qq', QQ_ID);
221
-
222
- return fetch(`https://qmsg.zendee.cn/send/${QMSG_KEY}`, {
223
- method: 'POST',
224
- header: form.getHeaders(),
225
- body: form,
226
- }).then((resp) => resp.json());
227
- }
228
-
229
- async telegram(self, parent) {
230
- const { TG_BOT_TOKEN, TG_CHAT_ID, SITE_NAME, SITE_URL } = process.env;
231
-
232
- if (!TG_BOT_TOKEN || !TG_CHAT_ID) {
233
- return false;
234
- }
235
-
236
- let commentLink = '';
237
- const href = self.comment.match(/<a href="(.*?)">(.*?)<\/a>/g);
238
-
239
- if (href !== null) {
240
- for (var i = 0; i < href.length; i++) {
241
- href[i] =
242
- '[Link: ' +
243
- href[i].replace(/<a href="(.*?)">(.*?)<\/a>/g, '$2') +
244
- '](' +
245
- href[i].replace(/<a href="(.*?)">(.*?)<\/a>/g, '$1') +
246
- ') ';
247
- commentLink = commentLink + href[i];
248
- }
249
- }
250
- if (commentLink !== '') {
251
- commentLink = `\n` + commentLink + `\n`;
252
- }
253
- const comment = self.comment
254
- .replace(/<a href="(.*?)">(.*?)<\/a>/g, '[Link:$2]')
255
- .replace(/<[^>]+>/g, '');
256
-
257
- const contentTG =
258
- think.config('TGTemplate') ||
259
- `💬 *[{{site.name}}]({{site.url}}) 有新评论啦*
260
-
261
- *{{self.nick}}* 回复说:
262
-
263
- \`\`\`
264
- {{self.comment-}}
265
- \`\`\`
266
- {{-self.commentLink}}
267
- *邮箱:*\`{{self.mail}}\`
268
- *审核:*{{self.status}}
269
-
270
- 仅供评论预览,点击[查看完整內容]({{site.postUrl}})`;
271
-
272
- const data = {
273
- self: {
274
- ...self,
275
- comment,
276
- commentLink,
277
- },
278
- parent,
279
- site: {
280
- name: SITE_NAME,
281
- url: SITE_URL,
282
- postUrl: SITE_URL + self.url + '#' + self.objectId,
283
- },
284
- };
285
-
286
- const form = new FormData();
287
-
288
- form.append('text', this.ctx.locale(contentTG, data));
289
- form.append('chat_id', TG_CHAT_ID);
290
- form.append('parse_mode', 'MarkdownV2');
291
-
292
- const resp = await fetch(
293
- `https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage`,
294
- {
295
- method: 'POST',
296
- header: form.getHeaders(),
297
- body: form,
298
- }
299
- ).then((resp) => resp.json());
300
-
301
- if (!resp.ok) {
302
- console.log('Telegram Notification Failed:' + JSON.stringify(resp));
303
- }
304
- }
305
-
306
- async pushplus({ title, content }, self, parent) {
307
- const {
308
- PUSH_PLUS_KEY,
309
- PUSH_PLUS_TOPIC: topic,
310
- PUSH_PLUS_TEMPLATE: template,
311
- PUSH_PLUS_CHANNEL: channel,
312
- PUSH_PLUS_WEBHOOK: webhook,
313
- PUSH_PLUS_CALLBACKURL: callbackUrl,
314
- SITE_NAME,
315
- SITE_URL,
316
- } = process.env;
317
-
318
- if (!PUSH_PLUS_KEY) {
319
- return false;
320
- }
321
-
322
- const data = {
323
- self,
324
- parent,
325
- site: {
326
- name: SITE_NAME,
327
- url: SITE_URL,
328
- postUrl: SITE_URL + self.url + '#' + self.objectId,
329
- },
330
- };
331
-
332
- title = this.ctx.locale(title, data);
333
- content = this.ctx.locale(content, data);
334
-
335
- const form = new FormData();
336
-
337
- topic && form.append('topic', topic);
338
- template && form.append('template', template);
339
- channel && form.append('channel', channel);
340
- webhook && form.append('webhook', webhook);
341
- callbackUrl && form.append('callbackUrl', callbackUrl);
342
- title && form.append('title', title);
343
- content && form.append('content', content);
344
-
345
- return fetch(`http://www.pushplus.plus/send/${PUSH_PLUS_KEY}`, {
346
- method: 'POST',
347
- header: form.getHeaders(),
348
- body: form,
349
- }).then((resp) => resp.json());
350
- }
351
-
352
- async discord({ title, content }, self, parent) {
353
- const { DISCORD_WEBHOOK, SITE_NAME, SITE_URL } = process.env;
354
-
355
- if (!DISCORD_WEBHOOK) {
356
- return false;
357
- }
358
-
359
- const data = {
360
- self,
361
- parent,
362
- site: {
363
- name: SITE_NAME,
364
- url: SITE_URL,
365
- postUrl: SITE_URL + self.url + '#' + self.objectId,
366
- },
367
- };
368
-
369
- title = this.ctx.locale(title, data);
370
- content = this.ctx.locale(
371
- think.config('DiscordTemplate') ||
372
- `💬 {{site.name|safe}} 有新评论啦
373
- 【评论者昵称】:{{self.nick}}
374
- 【评论者邮箱】:{{self.mail}}
375
- 【内容】:{{self.comment}}
376
- 【地址】:{{site.postUrl}}`,
377
- data
378
- );
379
-
380
- const form = new FormData();
381
-
382
- form.append('content', `${title}\n${content}`);
383
-
384
- return fetch(DISCORD_WEBHOOK, {
385
- method: 'POST',
386
- header: form.getHeaders(),
387
- body: form,
388
- }).then((resp) => resp.json());
389
- }
390
-
391
- async lark({ title, content }, self, parent) {
392
- const { LARK_WEBHOOK, LARK_SECRET, SITE_NAME, SITE_URL } = process.env;
393
-
394
- if (!LARK_WEBHOOK) {
395
- return false;
396
- }
397
-
398
- self.comment = self.comment.replace(/(<([^>]+)>)/gi, '');
399
-
400
- const data = {
401
- self,
402
- parent,
403
- site: {
404
- name: SITE_NAME,
405
- url: SITE_URL,
406
- postUrl: SITE_URL + self.url + '#' + self.objectId,
407
- },
408
- };
409
-
410
- content = nunjucks.renderString(
411
- think.config('LarkTemplate') ||
412
- `【网站名称】:{{site.name|safe}} \n【评论者昵称】:{{self.nick}}\n【评论者邮箱】:{{self.mail}}\n【内容】:{{self.comment}}【地址】:{{site.postUrl}}`,
413
- data
414
- );
415
-
416
- const post = {
417
- en_us: {
418
- title: this.ctx.locale(title, data),
419
- content: [
420
- [
421
- {
422
- tag: 'text',
423
- text: content,
424
- },
425
- ],
426
- ],
427
- },
428
- };
429
-
430
- let signData = {};
431
- const msg = {
432
- msg_type: 'post',
433
- content: {
434
- post,
435
- },
436
- };
437
-
438
- const sign = (timestamp, secret) => {
439
- const signStr = timestamp + '\n' + secret;
440
-
441
- return crypto.createHmac('sha256', signStr).update('').digest('base64');
442
- };
443
-
444
- if (LARK_SECRET) {
445
- const timestamp = parseInt(+new Date() / 1000);
446
-
447
- signData = { timestamp: timestamp, sign: sign(timestamp, LARK_SECRET) };
448
- }
449
-
450
- const resp = await fetch(LARK_WEBHOOK, {
451
- method: 'POST',
452
- headers: {
453
- 'Content-Type': 'application/json',
454
- },
455
- body: JSON.stringify({
456
- ...signData,
457
- ...msg,
458
- }),
459
- }).then((resp) => resp.json());
460
-
461
- if (resp.status !== 200) {
462
- console.log('Lark Notification Failed:' + JSON.stringify(resp));
463
- }
464
-
465
- console.log('FeiShu Notification Success:' + JSON.stringify(resp));
466
- }
467
-
468
- async run(comment, parent, disableAuthorNotify = false) {
469
- const { AUTHOR_EMAIL, DISABLE_AUTHOR_NOTIFY } = process.env;
470
- const { mailSubject, mailTemplate, mailSubjectAdmin, mailTemplateAdmin } =
471
- think.config();
472
- const AUTHOR = AUTHOR_EMAIL;
473
-
474
- const mailList = [];
475
- const isAuthorComment = AUTHOR
476
- ? comment.mail.toLowerCase() === AUTHOR.toLowerCase()
477
- : false;
478
- const isReplyAuthor = AUTHOR
479
- ? parent && parent.mail.toLowerCase() === AUTHOR.toLowerCase()
480
- : false;
481
- const isCommentSelf =
482
- parent && parent.mail.toLowerCase() === comment.mail.toLowerCase();
483
-
484
- const title = mailSubjectAdmin || 'MAIL_SUBJECT_ADMIN';
485
- const content = mailTemplateAdmin || 'MAIL_TEMPLATE_ADMIN';
486
-
487
- if (!DISABLE_AUTHOR_NOTIFY && !isAuthorComment && !disableAuthorNotify) {
488
- const wechat = await this.wechat({ title, content }, comment, parent);
489
- const qywxAmWechat = await this.qywxAmWechat(
490
- { title, content },
491
- comment,
492
- parent
493
- );
494
- const qq = await this.qq(comment, parent);
495
- const telegram = await this.telegram(comment, parent);
496
- const pushplus = await this.pushplus({ title, content }, comment, parent);
497
- const discord = await this.discord({ title, content }, comment, parent);
498
- const lark = await this.lark({ title, content }, comment, parent);
499
-
500
- if (
501
- [wechat, qq, telegram, qywxAmWechat, pushplus, discord, lark].every(
502
- think.isEmpty
503
- )
504
- ) {
505
- mailList.push({ to: AUTHOR, title, content });
506
- }
507
- }
508
-
509
- const disallowList = ['github', 'twitter', 'facebook'].map(
510
- (social) => 'mail.' + social
511
- );
512
- const fakeMail = new RegExp(`@(${disallowList.join('|')})$`, 'i');
513
-
514
- if (
515
- parent &&
516
- !fakeMail.test(parent.mail) &&
517
- !isCommentSelf &&
518
- !isReplyAuthor &&
519
- comment.status !== 'waiting'
520
- ) {
521
- mailList.push({
522
- to: parent.mail,
523
- title: mailSubject || 'MAIL_SUBJECT',
524
- content: mailTemplate || 'MAIL_TEMPLATE',
525
- });
526
- }
527
-
528
- for (let i = 0; i < mailList.length; i++) {
529
- try {
530
- const response = await this.mail(mailList[i], comment, parent);
531
-
532
- console.log('Notification mail send success: %s', response);
533
- } catch (e) {
534
- console.log('Mail send fail:', e);
535
- }
536
- }
537
- }
538
- };
@@ -1,31 +0,0 @@
1
- /* eslint-disable no-unused-vars */
2
-
3
- module.exports = class extends think.Service {
4
- constructor(tableName) {
5
- super();
6
- this.tableName = tableName;
7
- }
8
-
9
- async select(where, { desc, limit, offset, field } = {}) {
10
- //to be implemented
11
- }
12
-
13
- async count(where = {}, options = {}) {
14
- //to be implemented
15
- }
16
-
17
- async add(
18
- data,
19
- { access: { read = true, write = true } = { read: true, write: true } } = {}
20
- ) {
21
- //to be implemented
22
- }
23
-
24
- async update(data, where) {
25
- //to be implemented
26
- }
27
-
28
- async delete(where) {
29
- //to be implemented
30
- }
31
- };