Skip to content

Commit

Permalink
feat: v3.7.14
Browse files Browse the repository at this point in the history
  • Loading branch information
surmon-china committed Jan 19, 2022
1 parent 2c81bf5 commit 747142e
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 48 deletions.
43 changes: 26 additions & 17 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@

All notable changes to this project will be documented in this file.

### 3.7.14(2022-01-19)

**Feature**

- `express-rate-limit` > `@nestjs/throttler`
- **[Vote]** add throttler
- **[Disqus]** add throttler
- **[Comment]** add throttler

### 3.7.11(2022-01-06)

**Feature**

- [Disqus] cache for userinfo & thread
- **[Disqus]** cache for userinfo & thread

### 3.7.6(2022-01-05)

**Feature**

- [Article] random releted articles
- [Comment] improve email content
- [Vote] send email to admin when new vote
- **[Article]** random releted articles
- **[Comment]** improve email content
- **[Vote]** send email to admin when new vote

### 3.7.4(2022-01-01)

**Feature**

- [Comment] add `reviseIPLocation` service
- **[Comment]** add `reviseIPLocation` service

### 3.7.2(2021-12-31)

Expand All @@ -32,18 +41,18 @@ All notable changes to this project will be documented in this file.

**Feature**

- [Like] rename `Like` module to `Vote`
- [Disqus] add Disqus comment module
- [Auth] rename `gravatar` to `avatar`
- [Article] add `disabled_comment` field
- [Article] remove `t_content` field
- [Option] remove `icp` field
- [Option] rename `blacklist` to `blocklist`
- [Comment] remove `is_top` field
- [Comment] add `dislikes` field
- [Comment] hidden `ip`, `email` fields
- [Comment] add `email_hash` virtual field
- [Helper] IP location services to `ip-api.com` & `ipapi.co`
- **[Like]** rename `Like` module to `Vote`
- **[Disqus]** add Disqus comment module
- **[Auth]** rename `gravatar` to `avatar`
- **[Article]** add `disabled_comment` field
- **[Article]** remove `t_content` field
- **[Option]** remove `icp` field
- **[Option]** rename `blacklist` to `blocklist`
- **[Comment]** remove `is_top` field
- **[Comment]** add `dislikes` field
- **[Comment]** hidden `ip`, `email` fields
- **[Comment]** add `email_hash` virtual field
- **[Helper]** IP location services to `ip-api.com` & `ipapi.co`

**Chore**

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nodepress",
"version": "3.7.13",
"version": "3.7.14",
"description": "RESTful API service for Surmon.me blog",
"author": {
"name": "Surmon",
Expand Down Expand Up @@ -39,6 +39,7 @@
"@nestjs/jwt": "^8.0.0",
"@nestjs/passport": "^8.0.1",
"@nestjs/platform-express": "^8.2.4",
"@nestjs/throttler": "^2.0.0",
"@typegoose/auto-increment": "^1.0.0",
"@typegoose/typegoose": "^9.4.0",
"akismet-api": "^5.2.1",
Expand All @@ -53,7 +54,6 @@
"cookie-parser": "^1.4.6",
"cross-env": "^7.0.3",
"express": "^4.17.2",
"express-rate-limit": "^5.5.1",
"fast-xml-parser": "^4.0.0-beta.8",
"googleapis": "^92.0.0",
"helmet": "^4.6.0",
Expand Down
13 changes: 12 additions & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* @author Surmon <https://github.com/surmon-china>
*/

import { APP_INTERCEPTOR } from '@nestjs/core'
import { APP_INTERCEPTOR, APP_GUARD } from '@nestjs/core'
import { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler'
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'
import { AppController } from '@app/app.controller'

Expand Down Expand Up @@ -37,6 +38,12 @@ import { VoteModule } from '@app/modules/vote/vote.module'

@Module({
imports: [
// https://github.com/nestjs/throttler#readme
ThrottlerModule.forRoot({
ttl: 60 * 5, // 5 minutes
limit: 300, // 300 limit
ignoreUserAgents: [/googlebot/gi, /bingbot/gi, /baidubot/gi],
}),
HelperModule,
DatabaseModule,
CacheModule,
Expand All @@ -59,6 +66,10 @@ import { VoteModule } from '@app/modules/vote/vote.module'
provide: APP_INTERCEPTOR,
useClass: HttpCacheInterceptor,
},
{
provide: APP_GUARD,
useClass: ThrottlerGuard,
},
],
})
export class AppModule implements NestModule {
Expand Down
4 changes: 2 additions & 2 deletions src/filters/error.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class HttpExceptionFilter implements ExceptionFilter {
const data: HttpResponseError = {
status: ResponseStatus.Error,
message: isString(errorOption) ? errorOption : errorOption.message,
error: errorInfo.message || (isString(errorInfo) ? errorInfo : JSON.stringify(errorInfo)),
error: errorInfo?.message || (isString(errorInfo) ? errorInfo : JSON.stringify(errorInfo)),
debug: isDevEnv ? exception.stack : UNDEFINED,
}

Expand All @@ -37,6 +37,6 @@ export class HttpExceptionFilter implements ExceptionFilter {
data.message = data.message || `Invalid API: ${request.method} > ${request.url}`
}

return response.status(errorInfo.status || status).jsonp(data)
return response.status(errorInfo?.status || status).jsonp(data)
}
}
2 changes: 0 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import passport from 'passport'
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import compression from 'compression'
import rateLimit from 'express-rate-limit'
import { AppModule } from '@app/app.module'
import { NestFactory, Reflector } from '@nestjs/core'
import { ValidationPipe } from '@app/pipes/validation.pipe'
Expand All @@ -31,7 +30,6 @@ async function bootstrap() {
app.use(bodyParser.urlencoded({ extended: true }))
// MARK: keep v0.5 https://github.com/jaredhanson/passport/blob/master/CHANGELOG.md#changed
app.use(passport.initialize())
app.use(rateLimit({ max: 1000, windowMs: 15 * 60 * 1000 }))
app.useGlobalFilters(new HttpExceptionFilter())
app.useGlobalPipes(new ValidationPipe())
app.useGlobalInterceptors(
Expand Down
3 changes: 3 additions & 0 deletions src/modules/comment/comment.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import lodash from 'lodash'
import { Controller, Get, Put, Post, Patch, Delete, Body, UseGuards, HttpStatus } from '@nestjs/common'
import { Throttle } from '@nestjs/throttler'
import { JwtAuthGuard } from '@app/guards/auth.guard'
import { HumanizedJwtAuthGuard } from '@app/guards/humanized-auth.guard'
import { HttpProcessor } from '@app/decorators/http.decorator'
Expand Down Expand Up @@ -42,6 +43,8 @@ export class CommentController {
return this.commentService.paginater(querys, options, !isAuthenticated)
}

// 30 seconds > limit 6
@Throttle(6, 30)
@Post()
@HttpProcessor.handle('Create comment')
createComment(@Body() comment: CreateCommentBase, @QueryParams() { visitor }): Promise<Comment> {
Expand Down
5 changes: 4 additions & 1 deletion src/modules/disqus/disqus.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* @author Surmon <https://github.com/surmon-china>
*/

import { FileInterceptor } from '@nestjs/platform-express'
import {
Controller,
Get,
Expand All @@ -18,6 +17,8 @@ import {
Query,
UseInterceptors,
} from '@nestjs/common'
import { FileInterceptor } from '@nestjs/platform-express'
import { Throttle } from '@nestjs/throttler'
import { isProdEnv } from '@app/app.environment'
import { JwtAuthGuard } from '@app/guards/auth.guard'
import { HttpProcessor } from '@app/decorators/http.decorator'
Expand Down Expand Up @@ -101,6 +102,8 @@ export class DisqusController {
return this.disqusPublicService.makeSureThreadDetailCache(Number(query.post_id))
}

// 30 seconds > limit 6
@Throttle(6, 30)
@Post('comment')
@HttpProcessor.handle('Create universal comment')
createComment(
Expand Down
47 changes: 29 additions & 18 deletions src/modules/vote/vote.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { IsInt, IsDefined, IsIn, IsOptional, IsObject, ValidateNested } from 'class-validator'
import { Controller, Post, Body } from '@nestjs/common'
import { Throttle } from '@nestjs/throttler'
import { QueryParams } from '@app/decorators/query-params.decorator'
import { HttpProcessor } from '@app/decorators/http.decorator'
import { IPService, IPLocation } from '@app/processors/helper/helper.service.ip'
Expand Down Expand Up @@ -136,6 +137,8 @@ export class VoteController {
return result
}

// 1 hour > limit 10
@Throttle(10, 60 * 60)
@Post('/site')
@HttpProcessor.handle('Vote site')
async likeSite(
Expand All @@ -149,20 +152,24 @@ export class VoteController {
this.voteDisqusThread(CommentPostID.Guestbook, 1, token?.access_token).catch(() => {})
// email to admin
this.getAuthor(voteBody.author, token?.access_token).then(async (author) => {
this.emailToTargetVoteMessage({
to: APP_CONFIG.APP.ADMIN_EMAIL,
subject: `You have a new site vote`,
on: await this.getTargetTitle(CommentPostID.Guestbook),
vote: '+1',
author: author || 'Anonymous user',
location: await this.ipService.queryLocation(visitor.ip),
link: getPermalinkByID(CommentPostID.Guestbook),
})
if (author) {
this.emailToTargetVoteMessage({
to: APP_CONFIG.APP.ADMIN_EMAIL,
subject: `You have a new site vote`,
on: await this.getTargetTitle(CommentPostID.Guestbook),
vote: '+1',
author: author || 'Anonymous user',
location: await this.ipService.queryLocation(visitor.ip),
link: getPermalinkByID(CommentPostID.Guestbook),
})
}
})

return likes
}

// 1 minute > limit 15
@Throttle(15, 60)
@Post('/article')
@HttpProcessor.handle('Vote article')
async voteArticle(
Expand All @@ -176,20 +183,24 @@ export class VoteController {
this.voteDisqusThread(voteBody.article_id, voteBody.vote, token?.access_token).catch(() => {})
// email to admin
this.getAuthor(voteBody.author, token?.access_token).then(async (author) => {
this.emailToTargetVoteMessage({
to: APP_CONFIG.APP.ADMIN_EMAIL,
subject: `You have a new article vote`,
on: await this.getTargetTitle(voteBody.article_id),
vote: '+1',
author: author || 'Anonymous user',
location: await this.ipService.queryLocation(visitor.ip),
link: getPermalinkByID(voteBody.article_id),
})
if (author) {
this.emailToTargetVoteMessage({
to: APP_CONFIG.APP.ADMIN_EMAIL,
subject: `You have a new article vote`,
on: await this.getTargetTitle(voteBody.article_id),
vote: '+1',
author,
location: await this.ipService.queryLocation(visitor.ip),
link: getPermalinkByID(voteBody.article_id),
})
}
})

return likes
}

// 30 seconds > limit 10
@Throttle(10, 30)
@Post('/comment')
@HttpProcessor.handle('Vote comment')
async voteComment(
Expand Down
36 changes: 31 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,13 @@
optional "0.1.4"
tslib "2.3.1"

"@nestjs/throttler@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@nestjs/throttler/-/throttler-2.0.0.tgz#bb5f627cbaee369703d3d8d4ec7af6e4c6ab693a"
integrity sha512-N20iaRPqm0PNfZoCtcmwCoJzYBMUT9WveafFjGiQN0ov63RfVwzu0+bdv4AFxITd/t3vEDWoadzfUGyJBD43hw==
dependencies:
md5 "^2.2.1"

"@node-redis/client@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.1.tgz#ddca6021097ce1026fedc193cac8c36b05c6cad8"
Expand Down Expand Up @@ -1927,6 +1934,11 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==

[email protected]:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=

[email protected], chokidar@^3.4.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
Expand Down Expand Up @@ -2233,6 +2245,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"

[email protected]:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=

cssom@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
Expand Down Expand Up @@ -2923,11 +2940,6 @@ expect@^27.4.6:
jest-matcher-utils "^27.4.6"
jest-message-util "^27.4.6"

express-rate-limit@^5.5.1:
version "5.5.1"
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-5.5.1.tgz#110c23f6a65dfa96ab468eda95e71697bc6987a2"
integrity sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==

[email protected]:
version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
Expand Down Expand Up @@ -3757,6 +3769,11 @@ is-boolean-object@^1.1.0:
call-bind "^1.0.2"
has-tostringtag "^1.0.0"

is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==

is-callable@^1.1.4, is-callable@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
Expand Down Expand Up @@ -4748,6 +4765,15 @@ [email protected]:
dependencies:
tmpl "1.0.5"

md5@^2.2.1:
version "2.3.0"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
dependencies:
charenc "0.0.2"
crypt "0.0.2"
is-buffer "~1.1.6"

[email protected]:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
Expand Down

0 comments on commit 747142e

Please sign in to comment.