import cors from 'cors'
import express from 'express'
-import RateLimit from 'express-rate-limit'
+import { buildRateLimiter } from '@server/middlewares'
import { HttpStatusCode } from '../../../shared/models'
import { badRequest } from '../../helpers/express-utils'
import { CONFIG } from '../../initializers/config'
credentials: true
}))
-const apiRateLimiter = RateLimit({
+const apiRateLimiter = buildRateLimiter({
windowMs: CONFIG.RATES_LIMIT.API.WINDOW_MS,
max: CONFIG.RATES_LIMIT.API.MAX
})
import express from 'express'
-import RateLimit from 'express-rate-limit'
import { tokensRouter } from '@server/controllers/api/users/token'
import { Hooks } from '@server/lib/plugins/hooks'
import { OAuthTokenModel } from '@server/models/oauth/oauth-token'
import { Redis } from '../../../lib/redis'
import { buildUser, createUserAccountAndChannelAndPlaylist, sendVerifyUserEmail } from '../../../lib/user'
import {
+ adminUsersSortValidator,
asyncMiddleware,
asyncRetryTransactionMiddleware,
authenticate,
+ buildRateLimiter,
ensureUserHasRight,
ensureUserRegistrationAllowed,
ensureUserRegistrationAllowedForIP,
usersListValidator,
usersRegisterValidator,
usersRemoveValidator,
- adminUsersSortValidator,
usersUpdateValidator
} from '../../../middlewares'
import {
const auditLogger = auditLoggerFactory('users')
-const signupRateLimiter = RateLimit({
+const signupRateLimiter = buildRateLimiter({
windowMs: CONFIG.RATES_LIMIT.SIGNUP.WINDOW_MS,
max: CONFIG.RATES_LIMIT.SIGNUP.MAX,
skipFailedRequests: true
})
-const askSendEmailLimiter = RateLimit({
+const askSendEmailLimiter = buildRateLimiter({
windowMs: CONFIG.RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS,
max: CONFIG.RATES_LIMIT.ASK_SEND_EMAIL.MAX
})
import express from 'express'
-import RateLimit from 'express-rate-limit'
import { logger } from '@server/helpers/logger'
import { CONFIG } from '@server/initializers/config'
import { getAuthNameFromRefreshGrant, getBypassFromExternalAuth, getBypassFromPasswordGrant } from '@server/lib/auth/external-auth'
import { handleOAuthToken } from '@server/lib/auth/oauth'
import { BypassLogin, revokeToken } from '@server/lib/auth/oauth-model'
import { Hooks } from '@server/lib/plugins/hooks'
-import { asyncMiddleware, authenticate, openapiOperationDoc } from '@server/middlewares'
+import { asyncMiddleware, authenticate, buildRateLimiter, openapiOperationDoc } from '@server/middlewares'
import { buildUUID } from '@shared/extra-utils'
import { ScopedToken } from '@shared/models/users/user-scoped-token'
const tokensRouter = express.Router()
-const loginRateLimiter = RateLimit({
+const loginRateLimiter = buildRateLimiter({
windowMs: CONFIG.RATES_LIMIT.LOGIN.WINDOW_MS,
max: CONFIG.RATES_LIMIT.LOGIN.MAX
})
export * from './async'
export * from './auth'
export * from './pagination'
+export * from './rate-limiter'
export * from './robots'
export * from './servers'
export * from './sort'
--- /dev/null
+import { UserRole } from '@shared/models'
+import RateLimit from 'express-rate-limit'
+import { optionalAuthenticate } from './auth'
+
+const whitelistRoles = new Set([ UserRole.ADMINISTRATOR, UserRole.MODERATOR ])
+
+function buildRateLimiter (options: {
+ windowMs: number
+ max: number
+ skipFailedRequests?: boolean
+}) {
+ return RateLimit({
+ windowMs: options.windowMs,
+ max: options.max,
+ skipFailedRequests: options.skipFailedRequests,
+
+ handler: (req, res, next, options) => {
+ return optionalAuthenticate(req, res, () => {
+ if (res.locals.authenticated === true && whitelistRoles.has(res.locals.oauth.token.User.role)) {
+ return next()
+ }
+
+ return res.status(options.statusCode).send(options.message)
+ })
+ }
+ })
+}
+
+export {
+ buildRateLimiter
+}
describe('Test application behind a reverse proxy', function () {
let server: PeerTubeServer
+ let userAccessToken: string
let videoId: string
before(async function () {
server = await createSingleServer(1, config)
await setAccessTokensToServers([ server ])
+ userAccessToken = await server.users.generateUserAndToken('user')
+
const { uuid } = await server.videos.upload()
videoId = uuid
})
it('Should rate limit logins', async function () {
const user = { username: 'root', password: 'fail' }
- for (let i = 0; i < 19; i++) {
+ for (let i = 0; i < 18; i++) {
await server.login.login({ user, expectedStatus: HttpStatusCode.BAD_REQUEST_400 })
}
await server.videos.get({ id: videoId, expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 })
})
+ it('Should rate limit API calls with a user but not with an admin', async function () {
+ await server.videos.get({ id: videoId, token: userAccessToken, expectedStatus: HttpStatusCode.TOO_MANY_REQUESTS_429 })
+
+ await server.videos.get({ id: videoId, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
+ })
+
after(async function () {
await cleanupTests([ server ])
})