Add more rate limits
This commit is contained in:
parent
9901c8d690
commit
97583d0023
|
@ -36,6 +36,26 @@ rates_limit:
|
||||||
# 10 attempts in 10 min
|
# 10 attempts in 10 min
|
||||||
window: 10 minutes
|
window: 10 minutes
|
||||||
max: 10
|
max: 10
|
||||||
|
plugins:
|
||||||
|
# 500 attempts in 10 seconds (we also serve plugin static files)
|
||||||
|
window: 10 seconds
|
||||||
|
max: 500
|
||||||
|
well_known:
|
||||||
|
# 200 attempts in 10 seconds
|
||||||
|
window: 10 seconds
|
||||||
|
max: 200
|
||||||
|
feeds:
|
||||||
|
# 50 attempts in 10 seconds
|
||||||
|
window: 10 seconds
|
||||||
|
max: 50
|
||||||
|
activity_pub:
|
||||||
|
# 500 attempts in 10 seconds (we can have many AP requests)
|
||||||
|
window: 10 seconds
|
||||||
|
max: 500
|
||||||
|
client: # HTML files generated by PeerTube
|
||||||
|
# 500 attempts in 10 seconds (to not break crawlers)
|
||||||
|
window: 10 seconds
|
||||||
|
max: 500
|
||||||
|
|
||||||
oauth2:
|
oauth2:
|
||||||
token_lifetime:
|
token_lifetime:
|
||||||
|
|
|
@ -34,6 +34,26 @@ rates_limit:
|
||||||
# 10 attempts in 10 min
|
# 10 attempts in 10 min
|
||||||
window: 10 minutes
|
window: 10 minutes
|
||||||
max: 10
|
max: 10
|
||||||
|
plugins:
|
||||||
|
# 500 attempts in 10 seconds (we also serve plugin static files)
|
||||||
|
window: 10 seconds
|
||||||
|
max: 500
|
||||||
|
well_known:
|
||||||
|
# 200 attempts in 10 seconds
|
||||||
|
window: 10 seconds
|
||||||
|
max: 200
|
||||||
|
feeds:
|
||||||
|
# 50 attempts in 10 seconds
|
||||||
|
window: 10 seconds
|
||||||
|
max: 50
|
||||||
|
activity_pub:
|
||||||
|
# 500 attempts in 10 seconds (we can have many AP requests)
|
||||||
|
window: 10 seconds
|
||||||
|
max: 500
|
||||||
|
client: # HTML files generated by PeerTube
|
||||||
|
# 500 attempts in 10 seconds (to not break crawlers)
|
||||||
|
window: 10 seconds
|
||||||
|
max: 500
|
||||||
|
|
||||||
oauth2:
|
oauth2:
|
||||||
token_lifetime:
|
token_lifetime:
|
||||||
|
|
|
@ -115,7 +115,7 @@ import {
|
||||||
pluginsRouter,
|
pluginsRouter,
|
||||||
trackerRouter,
|
trackerRouter,
|
||||||
createWebsocketTrackerServer,
|
createWebsocketTrackerServer,
|
||||||
botsRouter,
|
sitemapRouter,
|
||||||
downloadRouter
|
downloadRouter
|
||||||
} from './server/controllers'
|
} from './server/controllers'
|
||||||
import { advertiseDoNotTrack } from './server/middlewares/dnt'
|
import { advertiseDoNotTrack } from './server/middlewares/dnt'
|
||||||
|
@ -222,9 +222,7 @@ OpenTelemetryMetrics.Instance.init(app)
|
||||||
|
|
||||||
// ----------- Views, routes and static files -----------
|
// ----------- Views, routes and static files -----------
|
||||||
|
|
||||||
// API
|
app.use('/api/' + API_VERSION, apiRouter)
|
||||||
const apiRoute = '/api/' + API_VERSION
|
|
||||||
app.use(apiRoute, apiRouter)
|
|
||||||
|
|
||||||
// Services (oembed...)
|
// Services (oembed...)
|
||||||
app.use('/services', servicesRouter)
|
app.use('/services', servicesRouter)
|
||||||
|
@ -235,7 +233,7 @@ app.use('/', pluginsRouter)
|
||||||
app.use('/', activityPubRouter)
|
app.use('/', activityPubRouter)
|
||||||
app.use('/', feedsRouter)
|
app.use('/', feedsRouter)
|
||||||
app.use('/', trackerRouter)
|
app.use('/', trackerRouter)
|
||||||
app.use('/', botsRouter)
|
app.use('/', sitemapRouter)
|
||||||
|
|
||||||
// Static files
|
// Static files
|
||||||
app.use('/', staticRouter)
|
app.use('/', staticRouter)
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
getLocalVideoSharesActivityPubUrl
|
getLocalVideoSharesActivityPubUrl
|
||||||
} from '../../lib/activitypub/url'
|
} from '../../lib/activitypub/url'
|
||||||
import {
|
import {
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware,
|
asyncMiddleware,
|
||||||
ensureIsLocalChannel,
|
ensureIsLocalChannel,
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
@ -47,32 +48,38 @@ activityPubClientRouter.use(cors())
|
||||||
activityPubClientRouter.get(
|
activityPubClientRouter.get(
|
||||||
[ '/accounts?/:name', '/accounts?/:name/video-channels', '/a/:name', '/a/:name/video-channels' ],
|
[ '/accounts?/:name', '/accounts?/:name/video-channels', '/a/:name', '/a/:name/video-channels' ],
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(localAccountValidator),
|
||||||
asyncMiddleware(accountController)
|
asyncMiddleware(accountController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/followers',
|
activityPubClientRouter.get('/accounts?/:name/followers',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(localAccountValidator),
|
||||||
asyncMiddleware(accountFollowersController)
|
asyncMiddleware(accountFollowersController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/following',
|
activityPubClientRouter.get('/accounts?/:name/following',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(localAccountValidator),
|
||||||
asyncMiddleware(accountFollowingController)
|
asyncMiddleware(accountFollowingController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/playlists',
|
activityPubClientRouter.get('/accounts?/:name/playlists',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(localAccountValidator),
|
||||||
asyncMiddleware(accountPlaylistsController)
|
asyncMiddleware(accountPlaylistsController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/likes/:videoId',
|
activityPubClientRouter.get('/accounts?/:name/likes/:videoId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
||||||
asyncMiddleware(getAccountVideoRateValidatorFactory('like')),
|
asyncMiddleware(getAccountVideoRateValidatorFactory('like')),
|
||||||
asyncMiddleware(getAccountVideoRateFactory('like'))
|
asyncMiddleware(getAccountVideoRateFactory('like'))
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId',
|
activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
||||||
asyncMiddleware(getAccountVideoRateValidatorFactory('dislike')),
|
asyncMiddleware(getAccountVideoRateValidatorFactory('dislike')),
|
||||||
asyncMiddleware(getAccountVideoRateFactory('dislike'))
|
asyncMiddleware(getAccountVideoRateFactory('dislike'))
|
||||||
|
@ -81,47 +88,56 @@ activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId',
|
||||||
activityPubClientRouter.get(
|
activityPubClientRouter.get(
|
||||||
[ '/videos/watch/:id', '/w/:id' ],
|
[ '/videos/watch/:id', '/w/:id' ],
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
||||||
asyncMiddleware(videosCustomGetValidator('all')),
|
asyncMiddleware(videosCustomGetValidator('all')),
|
||||||
asyncMiddleware(videoController)
|
asyncMiddleware(videoController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/activity',
|
activityPubClientRouter.get('/videos/watch/:id/activity',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('all')),
|
asyncMiddleware(videosCustomGetValidator('all')),
|
||||||
asyncMiddleware(videoController)
|
asyncMiddleware(videoController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/announces',
|
activityPubClientRouter.get('/videos/watch/:id/announces',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
||||||
asyncMiddleware(videoAnnouncesController)
|
asyncMiddleware(videoAnnouncesController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/announces/:actorId',
|
activityPubClientRouter.get('/videos/watch/:id/announces/:actorId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosShareValidator),
|
asyncMiddleware(videosShareValidator),
|
||||||
asyncMiddleware(videoAnnounceController)
|
asyncMiddleware(videoAnnounceController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/likes',
|
activityPubClientRouter.get('/videos/watch/:id/likes',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
||||||
asyncMiddleware(videoLikesController)
|
asyncMiddleware(videoLikesController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/dislikes',
|
activityPubClientRouter.get('/videos/watch/:id/dislikes',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
||||||
asyncMiddleware(videoDislikesController)
|
asyncMiddleware(videoDislikesController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/comments',
|
activityPubClientRouter.get('/videos/watch/:id/comments',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
|
||||||
asyncMiddleware(videoCommentsController)
|
asyncMiddleware(videoCommentsController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',
|
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoCommentGetValidator),
|
asyncMiddleware(videoCommentGetValidator),
|
||||||
asyncMiddleware(videoCommentController)
|
asyncMiddleware(videoCommentController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity',
|
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoCommentGetValidator),
|
asyncMiddleware(videoCommentGetValidator),
|
||||||
asyncMiddleware(videoCommentController)
|
asyncMiddleware(videoCommentController)
|
||||||
)
|
)
|
||||||
|
@ -129,24 +145,28 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity
|
||||||
activityPubClientRouter.get(
|
activityPubClientRouter.get(
|
||||||
[ '/video-channels/:nameWithHost', '/video-channels/:nameWithHost/videos', '/c/:nameWithHost', '/c/:nameWithHost/videos' ],
|
[ '/video-channels/:nameWithHost', '/video-channels/:nameWithHost/videos', '/c/:nameWithHost', '/c/:nameWithHost/videos' ],
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureIsLocalChannel,
|
ensureIsLocalChannel,
|
||||||
asyncMiddleware(videoChannelController)
|
asyncMiddleware(videoChannelController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-channels/:nameWithHost/followers',
|
activityPubClientRouter.get('/video-channels/:nameWithHost/followers',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureIsLocalChannel,
|
ensureIsLocalChannel,
|
||||||
asyncMiddleware(videoChannelFollowersController)
|
asyncMiddleware(videoChannelFollowersController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-channels/:nameWithHost/following',
|
activityPubClientRouter.get('/video-channels/:nameWithHost/following',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureIsLocalChannel,
|
ensureIsLocalChannel,
|
||||||
asyncMiddleware(videoChannelFollowingController)
|
asyncMiddleware(videoChannelFollowingController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-channels/:nameWithHost/playlists',
|
activityPubClientRouter.get('/video-channels/:nameWithHost/playlists',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureIsLocalChannel,
|
ensureIsLocalChannel,
|
||||||
asyncMiddleware(videoChannelPlaylistsController)
|
asyncMiddleware(videoChannelPlaylistsController)
|
||||||
|
@ -154,11 +174,13 @@ activityPubClientRouter.get('/video-channels/:nameWithHost/playlists',
|
||||||
|
|
||||||
activityPubClientRouter.get('/redundancy/videos/:videoId/:resolution([0-9]+)(-:fps([0-9]+))?',
|
activityPubClientRouter.get('/redundancy/videos/:videoId/:resolution([0-9]+)(-:fps([0-9]+))?',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoFileRedundancyGetValidator),
|
asyncMiddleware(videoFileRedundancyGetValidator),
|
||||||
asyncMiddleware(videoRedundancyController)
|
asyncMiddleware(videoRedundancyController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/redundancy/streaming-playlists/:streamingPlaylistType/:videoId',
|
activityPubClientRouter.get('/redundancy/streaming-playlists/:streamingPlaylistType/:videoId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoPlaylistRedundancyGetValidator),
|
asyncMiddleware(videoPlaylistRedundancyGetValidator),
|
||||||
asyncMiddleware(videoRedundancyController)
|
asyncMiddleware(videoRedundancyController)
|
||||||
)
|
)
|
||||||
|
@ -166,17 +188,20 @@ activityPubClientRouter.get('/redundancy/streaming-playlists/:streamingPlaylistT
|
||||||
activityPubClientRouter.get(
|
activityPubClientRouter.get(
|
||||||
[ '/video-playlists/:playlistId', '/videos/watch/playlist/:playlistId', '/w/p/:playlistId' ],
|
[ '/video-playlists/:playlistId', '/videos/watch/playlist/:playlistId', '/w/p/:playlistId' ],
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoPlaylistsGetValidator('all')),
|
asyncMiddleware(videoPlaylistsGetValidator('all')),
|
||||||
asyncMiddleware(videoPlaylistController)
|
asyncMiddleware(videoPlaylistController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-playlists/:playlistId/videos/:playlistElementId',
|
activityPubClientRouter.get('/video-playlists/:playlistId/videos/:playlistElementId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoPlaylistElementAPGetValidator),
|
asyncMiddleware(videoPlaylistElementAPGetValidator),
|
||||||
asyncMiddleware(videoPlaylistElementController)
|
asyncMiddleware(videoPlaylistElementController)
|
||||||
)
|
)
|
||||||
|
|
||||||
activityPubClientRouter.get('/videos/local-viewer/:localViewerId',
|
activityPubClientRouter.get('/videos/local-viewer/:localViewerId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(getVideoLocalViewerValidator),
|
asyncMiddleware(getVideoLocalViewerValidator),
|
||||||
asyncMiddleware(getVideoLocalViewerController)
|
asyncMiddleware(getVideoLocalViewerController)
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { HttpStatusCode } from '../../../shared/models/http/http-error-codes'
|
||||||
import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity'
|
import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import {
|
import {
|
||||||
|
activityPubRateLimiter,
|
||||||
asyncMiddleware,
|
asyncMiddleware,
|
||||||
checkSignature,
|
checkSignature,
|
||||||
ensureIsLocalChannel,
|
ensureIsLocalChannel,
|
||||||
|
@ -17,6 +18,7 @@ import { activityPubValidator } from '../../middlewares/validators/activitypub/a
|
||||||
const inboxRouter = express.Router()
|
const inboxRouter = express.Router()
|
||||||
|
|
||||||
inboxRouter.post('/inbox',
|
inboxRouter.post('/inbox',
|
||||||
|
activityPubRateLimiter,
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
asyncMiddleware(checkSignature),
|
asyncMiddleware(checkSignature),
|
||||||
asyncMiddleware(activityPubValidator),
|
asyncMiddleware(activityPubValidator),
|
||||||
|
@ -24,13 +26,16 @@ inboxRouter.post('/inbox',
|
||||||
)
|
)
|
||||||
|
|
||||||
inboxRouter.post('/accounts/:name/inbox',
|
inboxRouter.post('/accounts/:name/inbox',
|
||||||
|
activityPubRateLimiter,
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
asyncMiddleware(checkSignature),
|
asyncMiddleware(checkSignature),
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(localAccountValidator),
|
||||||
asyncMiddleware(activityPubValidator),
|
asyncMiddleware(activityPubValidator),
|
||||||
inboxController
|
inboxController
|
||||||
)
|
)
|
||||||
|
|
||||||
inboxRouter.post('/video-channels/:nameWithHost/inbox',
|
inboxRouter.post('/video-channels/:nameWithHost/inbox',
|
||||||
|
activityPubRateLimiter,
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
asyncMiddleware(checkSignature),
|
asyncMiddleware(checkSignature),
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
|
||||||
import { activityPubClientRouter } from './client'
|
import { activityPubClientRouter } from './client'
|
||||||
import { inboxRouter } from './inbox'
|
import { inboxRouter } from './inbox'
|
||||||
import { outboxRouter } from './outbox'
|
import { outboxRouter } from './outbox'
|
||||||
|
|
|
@ -7,7 +7,13 @@ import { VideoPrivacy } from '../../../shared/models/videos'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { buildAudience } from '../../lib/activitypub/audience'
|
import { buildAudience } from '../../lib/activitypub/audience'
|
||||||
import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send'
|
import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send'
|
||||||
import { asyncMiddleware, ensureIsLocalChannel, localAccountValidator, videoChannelsNameWithHostValidator } from '../../middlewares'
|
import {
|
||||||
|
activityPubRateLimiter,
|
||||||
|
asyncMiddleware,
|
||||||
|
ensureIsLocalChannel,
|
||||||
|
localAccountValidator,
|
||||||
|
videoChannelsNameWithHostValidator
|
||||||
|
} from '../../middlewares'
|
||||||
import { apPaginationValidator } from '../../middlewares/validators/activitypub'
|
import { apPaginationValidator } from '../../middlewares/validators/activitypub'
|
||||||
import { VideoModel } from '../../models/video/video'
|
import { VideoModel } from '../../models/video/video'
|
||||||
import { activityPubResponse } from './utils'
|
import { activityPubResponse } from './utils'
|
||||||
|
@ -15,12 +21,14 @@ import { activityPubResponse } from './utils'
|
||||||
const outboxRouter = express.Router()
|
const outboxRouter = express.Router()
|
||||||
|
|
||||||
outboxRouter.get('/accounts/:name/outbox',
|
outboxRouter.get('/accounts/:name/outbox',
|
||||||
|
activityPubRateLimiter,
|
||||||
apPaginationValidator,
|
apPaginationValidator,
|
||||||
localAccountValidator,
|
localAccountValidator,
|
||||||
asyncMiddleware(outboxController)
|
asyncMiddleware(outboxController)
|
||||||
)
|
)
|
||||||
|
|
||||||
outboxRouter.get('/video-channels/:nameWithHost/outbox',
|
outboxRouter.get('/video-channels/:nameWithHost/outbox',
|
||||||
|
activityPubRateLimiter,
|
||||||
apPaginationValidator,
|
apPaginationValidator,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsNameWithHostValidator),
|
||||||
ensureIsLocalChannel,
|
ensureIsLocalChannel,
|
||||||
|
|
|
@ -5,27 +5,53 @@ import { join } from 'path'
|
||||||
import { logger } from '@server/helpers/logger'
|
import { logger } from '@server/helpers/logger'
|
||||||
import { CONFIG } from '@server/initializers/config'
|
import { CONFIG } from '@server/initializers/config'
|
||||||
import { Hooks } from '@server/lib/plugins/hooks'
|
import { Hooks } from '@server/lib/plugins/hooks'
|
||||||
|
import { root } from '@shared/core-utils'
|
||||||
import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '@shared/core-utils/i18n'
|
import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '@shared/core-utils/i18n'
|
||||||
import { HttpStatusCode } from '@shared/models'
|
import { HttpStatusCode } from '@shared/models'
|
||||||
import { root } from '@shared/core-utils'
|
|
||||||
import { STATIC_MAX_AGE } from '../initializers/constants'
|
import { STATIC_MAX_AGE } from '../initializers/constants'
|
||||||
import { ClientHtml, sendHTML, serveIndexHTML } from '../lib/client-html'
|
import { ClientHtml, sendHTML, serveIndexHTML } from '../lib/client-html'
|
||||||
import { asyncMiddleware, embedCSP } from '../middlewares'
|
import { asyncMiddleware, buildRateLimiter, embedCSP } from '../middlewares'
|
||||||
|
|
||||||
const clientsRouter = express.Router()
|
const clientsRouter = express.Router()
|
||||||
|
|
||||||
|
const clientsRateLimiter = buildRateLimiter({
|
||||||
|
windowMs: CONFIG.RATES_LIMIT.CLIENT.WINDOW_MS,
|
||||||
|
max: CONFIG.RATES_LIMIT.CLIENT.MAX
|
||||||
|
})
|
||||||
|
|
||||||
const distPath = join(root(), 'client', 'dist')
|
const distPath = join(root(), 'client', 'dist')
|
||||||
const testEmbedPath = join(distPath, 'standalone', 'videos', 'test-embed.html')
|
const testEmbedPath = join(distPath, 'standalone', 'videos', 'test-embed.html')
|
||||||
|
|
||||||
// Special route that add OpenGraph and oEmbed tags
|
// Special route that add OpenGraph and oEmbed tags
|
||||||
// Do not use a template engine for a so little thing
|
// Do not use a template engine for a so little thing
|
||||||
clientsRouter.use([ '/w/p/:id', '/videos/watch/playlist/:id' ], asyncMiddleware(generateWatchPlaylistHtmlPage))
|
clientsRouter.use([ '/w/p/:id', '/videos/watch/playlist/:id' ],
|
||||||
clientsRouter.use([ '/w/:id', '/videos/watch/:id' ], asyncMiddleware(generateWatchHtmlPage))
|
clientsRateLimiter,
|
||||||
clientsRouter.use([ '/accounts/:nameWithHost', '/a/:nameWithHost' ], asyncMiddleware(generateAccountHtmlPage))
|
asyncMiddleware(generateWatchPlaylistHtmlPage)
|
||||||
clientsRouter.use([ '/video-channels/:nameWithHost', '/c/:nameWithHost' ], asyncMiddleware(generateVideoChannelHtmlPage))
|
)
|
||||||
clientsRouter.use('/@:nameWithHost', asyncMiddleware(generateActorHtmlPage))
|
|
||||||
|
clientsRouter.use([ '/w/:id', '/videos/watch/:id' ],
|
||||||
|
clientsRateLimiter,
|
||||||
|
asyncMiddleware(generateWatchHtmlPage)
|
||||||
|
)
|
||||||
|
|
||||||
|
clientsRouter.use([ '/accounts/:nameWithHost', '/a/:nameWithHost' ],
|
||||||
|
clientsRateLimiter,
|
||||||
|
asyncMiddleware(generateAccountHtmlPage)
|
||||||
|
)
|
||||||
|
|
||||||
|
clientsRouter.use([ '/video-channels/:nameWithHost', '/c/:nameWithHost' ],
|
||||||
|
clientsRateLimiter,
|
||||||
|
asyncMiddleware(generateVideoChannelHtmlPage)
|
||||||
|
)
|
||||||
|
|
||||||
|
clientsRouter.use('/@:nameWithHost',
|
||||||
|
clientsRateLimiter,
|
||||||
|
asyncMiddleware(generateActorHtmlPage)
|
||||||
|
)
|
||||||
|
|
||||||
const embedMiddlewares = [
|
const embedMiddlewares = [
|
||||||
|
clientsRateLimiter,
|
||||||
|
|
||||||
CONFIG.CSP.ENABLED
|
CONFIG.CSP.ENABLED
|
||||||
? embedCSP
|
? embedCSP
|
||||||
: (req: express.Request, res: express.Response, next: express.NextFunction) => next(),
|
: (req: express.Request, res: express.Response, next: express.NextFunction) => next(),
|
||||||
|
@ -48,11 +74,11 @@ clientsRouter.use('/video-playlists/embed', ...embedMiddlewares)
|
||||||
|
|
||||||
const testEmbedController = (req: express.Request, res: express.Response) => res.sendFile(testEmbedPath)
|
const testEmbedController = (req: express.Request, res: express.Response) => res.sendFile(testEmbedPath)
|
||||||
|
|
||||||
clientsRouter.use('/videos/test-embed', testEmbedController)
|
clientsRouter.use('/videos/test-embed', clientsRateLimiter, testEmbedController)
|
||||||
clientsRouter.use('/video-playlists/test-embed', testEmbedController)
|
clientsRouter.use('/video-playlists/test-embed', clientsRateLimiter, testEmbedController)
|
||||||
|
|
||||||
// Dynamic PWA manifest
|
// Dynamic PWA manifest
|
||||||
clientsRouter.get('/manifest.webmanifest', asyncMiddleware(generateManifest))
|
clientsRouter.get('/manifest.webmanifest', clientsRateLimiter, asyncMiddleware(generateManifest))
|
||||||
|
|
||||||
// Static client overrides
|
// Static client overrides
|
||||||
// Must be consistent with static client overrides redirections in /support/nginx/peertube
|
// Must be consistent with static client overrides redirections in /support/nginx/peertube
|
||||||
|
@ -88,7 +114,10 @@ clientsRouter.use('/client/*', (req: express.Request, res: express.Response) =>
|
||||||
|
|
||||||
// Always serve index client page (the client is a single page application, let it handle routing)
|
// Always serve index client page (the client is a single page application, let it handle routing)
|
||||||
// Try to provide the right language index.html
|
// Try to provide the right language index.html
|
||||||
clientsRouter.use('/(:language)?', asyncMiddleware(serveIndexHTML))
|
clientsRouter.use('/(:language)?',
|
||||||
|
clientsRateLimiter,
|
||||||
|
asyncMiddleware(serveIndexHTML)
|
||||||
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ const { middleware: cacheRouteMiddleware } = cacheRouteFactory({
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
commentFeedsRouter.get('/feeds/video-comments.:format',
|
commentFeedsRouter.get('/video-comments.:format',
|
||||||
feedsFormatValidator,
|
feedsFormatValidator,
|
||||||
setFeedFormatContentType,
|
setFeedFormatContentType,
|
||||||
cacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
|
cacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
|
||||||
|
|
|
@ -1,13 +1,22 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
|
import { CONFIG } from '@server/initializers/config'
|
||||||
|
import { buildRateLimiter } from '@server/middlewares'
|
||||||
import { commentFeedsRouter } from './comment-feeds'
|
import { commentFeedsRouter } from './comment-feeds'
|
||||||
import { videoFeedsRouter } from './video-feeds'
|
import { videoFeedsRouter } from './video-feeds'
|
||||||
import { videoPodcastFeedsRouter } from './video-podcast-feeds'
|
import { videoPodcastFeedsRouter } from './video-podcast-feeds'
|
||||||
|
|
||||||
const feedsRouter = express.Router()
|
const feedsRouter = express.Router()
|
||||||
|
|
||||||
feedsRouter.use('/', commentFeedsRouter)
|
const feedsRateLimiter = buildRateLimiter({
|
||||||
feedsRouter.use('/', videoFeedsRouter)
|
windowMs: CONFIG.RATES_LIMIT.FEEDS.WINDOW_MS,
|
||||||
feedsRouter.use('/', videoPodcastFeedsRouter)
|
max: CONFIG.RATES_LIMIT.FEEDS.MAX
|
||||||
|
})
|
||||||
|
|
||||||
|
feedsRouter.use('/feeds', feedsRateLimiter)
|
||||||
|
|
||||||
|
feedsRouter.use('/feeds', commentFeedsRouter)
|
||||||
|
feedsRouter.use('/feeds', videoFeedsRouter)
|
||||||
|
feedsRouter.use('/feeds', videoPodcastFeedsRouter)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ const { middleware: cacheRouteMiddleware } = cacheRouteFactory({
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
videoFeedsRouter.get('/feeds/videos.:format',
|
videoFeedsRouter.get('/videos.:format',
|
||||||
videosSortValidator,
|
videosSortValidator,
|
||||||
setDefaultVideosSort,
|
setDefaultVideosSort,
|
||||||
feedsFormatValidator,
|
feedsFormatValidator,
|
||||||
|
@ -37,7 +37,7 @@ videoFeedsRouter.get('/feeds/videos.:format',
|
||||||
asyncMiddleware(generateVideoFeed)
|
asyncMiddleware(generateVideoFeed)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoFeedsRouter.get('/feeds/subscriptions.:format',
|
videoFeedsRouter.get('/subscriptions.:format',
|
||||||
videosSortValidator,
|
videosSortValidator,
|
||||||
setDefaultVideosSort,
|
setDefaultVideosSort,
|
||||||
feedsFormatValidator,
|
feedsFormatValidator,
|
||||||
|
|
|
@ -40,7 +40,7 @@ for (const event of ([ 'channel-updated', 'channel-deleted' ] as const)) {
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
videoPodcastFeedsRouter.get('/feeds/podcast/videos.xml',
|
videoPodcastFeedsRouter.get('/podcast/videos.xml',
|
||||||
setFeedPodcastContentType,
|
setFeedPodcastContentType,
|
||||||
videoFeedsPodcastSetCacheKey,
|
videoFeedsPodcastSetCacheKey,
|
||||||
podcastCacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
|
podcastCacheRouteMiddleware(ROUTE_CACHE_LIFETIME.FEEDS),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export * from './activitypub'
|
export * from './activitypub'
|
||||||
export * from './api'
|
export * from './api'
|
||||||
export * from './bots'
|
export * from './sitemap'
|
||||||
export * from './client'
|
export * from './client'
|
||||||
export * from './download'
|
export * from './download'
|
||||||
export * from './feeds'
|
export * from './feeds'
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { HttpStatusCode } from '@shared/models'
|
||||||
import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo/nodeinfo.model'
|
import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo/nodeinfo.model'
|
||||||
import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION, ROUTE_CACHE_LIFETIME } from '../initializers/constants'
|
import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION, ROUTE_CACHE_LIFETIME } from '../initializers/constants'
|
||||||
import { getThemeOrDefault } from '../lib/plugins/theme-utils'
|
import { getThemeOrDefault } from '../lib/plugins/theme-utils'
|
||||||
import { asyncMiddleware } from '../middlewares'
|
import { apiRateLimiter, asyncMiddleware } from '../middlewares'
|
||||||
import { cacheRoute } from '../middlewares/cache/cache'
|
import { cacheRoute } from '../middlewares/cache/cache'
|
||||||
import { UserModel } from '../models/user/user'
|
import { UserModel } from '../models/user/user'
|
||||||
import { VideoModel } from '../models/video/video'
|
import { VideoModel } from '../models/video/video'
|
||||||
|
@ -18,12 +18,14 @@ const miscRouter = express.Router()
|
||||||
miscRouter.use(cors())
|
miscRouter.use(cors())
|
||||||
|
|
||||||
miscRouter.use('/nodeinfo/:version.json',
|
miscRouter.use('/nodeinfo/:version.json',
|
||||||
|
apiRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.NODEINFO),
|
cacheRoute(ROUTE_CACHE_LIFETIME.NODEINFO),
|
||||||
asyncMiddleware(generateNodeinfo)
|
asyncMiddleware(generateNodeinfo)
|
||||||
)
|
)
|
||||||
|
|
||||||
// robots.txt service
|
// robots.txt service
|
||||||
miscRouter.get('/robots.txt',
|
miscRouter.get('/robots.txt',
|
||||||
|
apiRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.ROBOTS),
|
cacheRoute(ROUTE_CACHE_LIFETIME.ROBOTS),
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
res.type('text/plain')
|
res.type('text/plain')
|
||||||
|
@ -33,12 +35,14 @@ miscRouter.get('/robots.txt',
|
||||||
)
|
)
|
||||||
|
|
||||||
miscRouter.all('/teapot',
|
miscRouter.all('/teapot',
|
||||||
|
apiRateLimiter,
|
||||||
getCup,
|
getCup,
|
||||||
asyncMiddleware(serveIndexHTML)
|
asyncMiddleware(serveIndexHTML)
|
||||||
)
|
)
|
||||||
|
|
||||||
// security.txt service
|
// security.txt service
|
||||||
miscRouter.get('/security.txt',
|
miscRouter.get('/security.txt',
|
||||||
|
apiRateLimiter,
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
return res.redirect(HttpStatusCode.MOVED_PERMANENTLY_301, '/.well-known/security.txt')
|
return res.redirect(HttpStatusCode.MOVED_PERMANENTLY_301, '/.well-known/security.txt')
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { logger } from '@server/helpers/logger'
|
import { logger } from '@server/helpers/logger'
|
||||||
|
import { CONFIG } from '@server/initializers/config'
|
||||||
|
import { buildRateLimiter } from '@server/middlewares'
|
||||||
import { optionalAuthenticate } from '@server/middlewares/auth'
|
import { optionalAuthenticate } from '@server/middlewares/auth'
|
||||||
import { getCompleteLocale, is18nLocale } from '../../shared/core-utils/i18n'
|
import { getCompleteLocale, is18nLocale } from '../../shared/core-utils/i18n'
|
||||||
import { HttpStatusCode } from '../../shared/models/http/http-error-codes'
|
import { HttpStatusCode } from '../../shared/models/http/http-error-codes'
|
||||||
|
@ -18,57 +20,72 @@ const sendFileOptions = {
|
||||||
|
|
||||||
const pluginsRouter = express.Router()
|
const pluginsRouter = express.Router()
|
||||||
|
|
||||||
|
const pluginsRateLimiter = buildRateLimiter({
|
||||||
|
windowMs: CONFIG.RATES_LIMIT.PLUGINS.WINDOW_MS,
|
||||||
|
max: CONFIG.RATES_LIMIT.PLUGINS.MAX
|
||||||
|
})
|
||||||
|
|
||||||
pluginsRouter.get('/plugins/global.css',
|
pluginsRouter.get('/plugins/global.css',
|
||||||
|
pluginsRateLimiter,
|
||||||
servePluginGlobalCSS
|
servePluginGlobalCSS
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.get('/plugins/translations/:locale.json',
|
pluginsRouter.get('/plugins/translations/:locale.json',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginTranslations
|
getPluginTranslations
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.get('/plugins/:pluginName/:pluginVersion/auth/:authName',
|
pluginsRouter.get('/plugins/:pluginName/:pluginVersion/auth/:authName',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginValidator(PluginType.PLUGIN),
|
getPluginValidator(PluginType.PLUGIN),
|
||||||
getExternalAuthValidator,
|
getExternalAuthValidator,
|
||||||
handleAuthInPlugin
|
handleAuthInPlugin
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.get('/plugins/:pluginName/:pluginVersion/static/:staticEndpoint(*)',
|
pluginsRouter.get('/plugins/:pluginName/:pluginVersion/static/:staticEndpoint(*)',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginValidator(PluginType.PLUGIN),
|
getPluginValidator(PluginType.PLUGIN),
|
||||||
pluginStaticDirectoryValidator,
|
pluginStaticDirectoryValidator,
|
||||||
servePluginStaticDirectory
|
servePluginStaticDirectory
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.get('/plugins/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)',
|
pluginsRouter.get('/plugins/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginValidator(PluginType.PLUGIN),
|
getPluginValidator(PluginType.PLUGIN),
|
||||||
pluginStaticDirectoryValidator,
|
pluginStaticDirectoryValidator,
|
||||||
servePluginClientScripts
|
servePluginClientScripts
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.use('/plugins/:pluginName/router',
|
pluginsRouter.use('/plugins/:pluginName/router',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginValidator(PluginType.PLUGIN, false),
|
getPluginValidator(PluginType.PLUGIN, false),
|
||||||
optionalAuthenticate,
|
optionalAuthenticate,
|
||||||
servePluginCustomRoutes
|
servePluginCustomRoutes
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.use('/plugins/:pluginName/:pluginVersion/router',
|
pluginsRouter.use('/plugins/:pluginName/:pluginVersion/router',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginValidator(PluginType.PLUGIN),
|
getPluginValidator(PluginType.PLUGIN),
|
||||||
optionalAuthenticate,
|
optionalAuthenticate,
|
||||||
servePluginCustomRoutes
|
servePluginCustomRoutes
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.get('/themes/:pluginName/:pluginVersion/static/:staticEndpoint(*)',
|
pluginsRouter.get('/themes/:pluginName/:pluginVersion/static/:staticEndpoint(*)',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginValidator(PluginType.THEME),
|
getPluginValidator(PluginType.THEME),
|
||||||
pluginStaticDirectoryValidator,
|
pluginStaticDirectoryValidator,
|
||||||
servePluginStaticDirectory
|
servePluginStaticDirectory
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.get('/themes/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)',
|
pluginsRouter.get('/themes/:pluginName/:pluginVersion/client-scripts/:staticEndpoint(*)',
|
||||||
|
pluginsRateLimiter,
|
||||||
getPluginValidator(PluginType.THEME),
|
getPluginValidator(PluginType.THEME),
|
||||||
pluginStaticDirectoryValidator,
|
pluginStaticDirectoryValidator,
|
||||||
servePluginClientScripts
|
servePluginClientScripts
|
||||||
)
|
)
|
||||||
|
|
||||||
pluginsRouter.get('/themes/:themeName/:themeVersion/css/:staticEndpoint(*)',
|
pluginsRouter.get('/themes/:themeName/:themeVersion/css/:staticEndpoint(*)',
|
||||||
|
pluginsRateLimiter,
|
||||||
serveThemeCSSValidator,
|
serveThemeCSSValidator,
|
||||||
serveThemeCSSDirectory
|
serveThemeCSSDirectory
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,17 +2,19 @@ import express from 'express'
|
||||||
import { MChannelSummary } from '@server/types/models'
|
import { MChannelSummary } from '@server/types/models'
|
||||||
import { escapeHTML } from '@shared/core-utils/renderer'
|
import { escapeHTML } from '@shared/core-utils/renderer'
|
||||||
import { EMBED_SIZE, PREVIEWS_SIZE, THUMBNAILS_SIZE, WEBSERVER } from '../initializers/constants'
|
import { EMBED_SIZE, PREVIEWS_SIZE, THUMBNAILS_SIZE, WEBSERVER } from '../initializers/constants'
|
||||||
import { asyncMiddleware, oembedValidator } from '../middlewares'
|
import { apiRateLimiter, asyncMiddleware, oembedValidator } from '../middlewares'
|
||||||
import { accountNameWithHostGetValidator } from '../middlewares/validators'
|
import { accountNameWithHostGetValidator } from '../middlewares/validators'
|
||||||
import { forceNumber } from '@shared/core-utils'
|
import { forceNumber } from '@shared/core-utils'
|
||||||
|
|
||||||
const servicesRouter = express.Router()
|
const servicesRouter = express.Router()
|
||||||
|
|
||||||
servicesRouter.use('/oembed',
|
servicesRouter.use('/oembed',
|
||||||
|
apiRateLimiter,
|
||||||
asyncMiddleware(oembedValidator),
|
asyncMiddleware(oembedValidator),
|
||||||
generateOEmbed
|
generateOEmbed
|
||||||
)
|
)
|
||||||
servicesRouter.use('/redirect/accounts/:accountName',
|
servicesRouter.use('/redirect/accounts/:accountName',
|
||||||
|
apiRateLimiter,
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
asyncMiddleware(accountNameWithHostGetValidator),
|
||||||
redirectToAccountUrl
|
redirectToAccountUrl
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,17 +5,16 @@ import { logger } from '@server/helpers/logger'
|
||||||
import { getServerActor } from '@server/models/application/application'
|
import { getServerActor } from '@server/models/application/application'
|
||||||
import { buildNSFWFilter } from '../helpers/express-utils'
|
import { buildNSFWFilter } from '../helpers/express-utils'
|
||||||
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
|
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
|
||||||
import { asyncMiddleware } from '../middlewares'
|
import { apiRateLimiter, asyncMiddleware } from '../middlewares'
|
||||||
import { cacheRoute } from '../middlewares/cache/cache'
|
import { cacheRoute } from '../middlewares/cache/cache'
|
||||||
import { AccountModel } from '../models/account/account'
|
import { AccountModel } from '../models/account/account'
|
||||||
import { VideoModel } from '../models/video/video'
|
import { VideoModel } from '../models/video/video'
|
||||||
import { VideoChannelModel } from '../models/video/video-channel'
|
import { VideoChannelModel } from '../models/video/video-channel'
|
||||||
|
|
||||||
const botsRouter = express.Router()
|
const sitemapRouter = express.Router()
|
||||||
|
|
||||||
// Special route that add OpenGraph and oEmbed tags
|
sitemapRouter.use('/sitemap.xml',
|
||||||
// Do not use a template engine for a so little thing
|
apiRateLimiter,
|
||||||
botsRouter.use('/sitemap.xml',
|
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.SITEMAP),
|
cacheRoute(ROUTE_CACHE_LIFETIME.SITEMAP),
|
||||||
asyncMiddleware(getSitemap)
|
asyncMiddleware(getSitemap)
|
||||||
)
|
)
|
||||||
|
@ -23,7 +22,7 @@ botsRouter.use('/sitemap.xml',
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
botsRouter
|
sitemapRouter
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
|
@ -1,7 +1,7 @@
|
||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { asyncMiddleware, handleStaticError, webfingerValidator } from '@server/middlewares'
|
import { asyncMiddleware, buildRateLimiter, handleStaticError, webfingerValidator } from '@server/middlewares'
|
||||||
import { root } from '@shared/core-utils'
|
import { root } from '@shared/core-utils'
|
||||||
import { CONFIG } from '../initializers/config'
|
import { CONFIG } from '../initializers/config'
|
||||||
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
|
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
|
||||||
|
@ -9,14 +9,21 @@ import { cacheRoute } from '../middlewares/cache/cache'
|
||||||
|
|
||||||
const wellKnownRouter = express.Router()
|
const wellKnownRouter = express.Router()
|
||||||
|
|
||||||
|
const wellKnownRateLimiter = buildRateLimiter({
|
||||||
|
windowMs: CONFIG.RATES_LIMIT.WELL_KNOWN.WINDOW_MS,
|
||||||
|
max: CONFIG.RATES_LIMIT.WELL_KNOWN.MAX
|
||||||
|
})
|
||||||
|
|
||||||
wellKnownRouter.use(cors())
|
wellKnownRouter.use(cors())
|
||||||
|
|
||||||
wellKnownRouter.get('/.well-known/webfinger',
|
wellKnownRouter.get('/.well-known/webfinger',
|
||||||
|
wellKnownRateLimiter,
|
||||||
asyncMiddleware(webfingerValidator),
|
asyncMiddleware(webfingerValidator),
|
||||||
webfingerController
|
webfingerController
|
||||||
)
|
)
|
||||||
|
|
||||||
wellKnownRouter.get('/.well-known/security.txt',
|
wellKnownRouter.get('/.well-known/security.txt',
|
||||||
|
wellKnownRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.SECURITYTXT),
|
cacheRoute(ROUTE_CACHE_LIFETIME.SECURITYTXT),
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
res.type('text/plain')
|
res.type('text/plain')
|
||||||
|
@ -26,6 +33,7 @@ wellKnownRouter.get('/.well-known/security.txt',
|
||||||
|
|
||||||
// nodeinfo service
|
// nodeinfo service
|
||||||
wellKnownRouter.use('/.well-known/nodeinfo',
|
wellKnownRouter.use('/.well-known/nodeinfo',
|
||||||
|
wellKnownRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.NODEINFO),
|
cacheRoute(ROUTE_CACHE_LIFETIME.NODEINFO),
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
return res.json({
|
return res.json({
|
||||||
|
@ -41,6 +49,7 @@ wellKnownRouter.use('/.well-known/nodeinfo',
|
||||||
|
|
||||||
// dnt-policy.txt service (see https://www.eff.org/dnt-policy)
|
// dnt-policy.txt service (see https://www.eff.org/dnt-policy)
|
||||||
wellKnownRouter.use('/.well-known/dnt-policy.txt',
|
wellKnownRouter.use('/.well-known/dnt-policy.txt',
|
||||||
|
wellKnownRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.DNT_POLICY),
|
cacheRoute(ROUTE_CACHE_LIFETIME.DNT_POLICY),
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
res.type('text/plain')
|
res.type('text/plain')
|
||||||
|
@ -51,18 +60,21 @@ wellKnownRouter.use('/.well-known/dnt-policy.txt',
|
||||||
|
|
||||||
// dnt service (see https://www.w3.org/TR/tracking-dnt/#status-resource)
|
// dnt service (see https://www.w3.org/TR/tracking-dnt/#status-resource)
|
||||||
wellKnownRouter.use('/.well-known/dnt/',
|
wellKnownRouter.use('/.well-known/dnt/',
|
||||||
|
wellKnownRateLimiter,
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
res.json({ tracking: 'N' })
|
res.json({ tracking: 'N' })
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
wellKnownRouter.use('/.well-known/change-password',
|
wellKnownRouter.use('/.well-known/change-password',
|
||||||
|
wellKnownRateLimiter,
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
res.redirect('/my-account/settings')
|
res.redirect('/my-account/settings')
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
wellKnownRouter.use('/.well-known/host-meta',
|
wellKnownRouter.use('/.well-known/host-meta',
|
||||||
|
wellKnownRateLimiter,
|
||||||
(_, res: express.Response) => {
|
(_, res: express.Response) => {
|
||||||
res.type('application/xml')
|
res.type('application/xml')
|
||||||
|
|
||||||
|
@ -76,6 +88,7 @@ wellKnownRouter.use('/.well-known/host-meta',
|
||||||
)
|
)
|
||||||
|
|
||||||
wellKnownRouter.use('/.well-known/',
|
wellKnownRouter.use('/.well-known/',
|
||||||
|
wellKnownRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.WELL_KNOWN),
|
cacheRoute(ROUTE_CACHE_LIFETIME.WELL_KNOWN),
|
||||||
express.static(CONFIG.STORAGE.WELL_KNOWN_DIR, { fallthrough: false }),
|
express.static(CONFIG.STORAGE.WELL_KNOWN_DIR, { fallthrough: false }),
|
||||||
handleStaticError
|
handleStaticError
|
||||||
|
|
|
@ -56,7 +56,11 @@ function checkMissedConfig () {
|
||||||
'followers.instance.enabled', 'followers.instance.manual_approval',
|
'followers.instance.enabled', 'followers.instance.manual_approval',
|
||||||
'tracker.enabled', 'tracker.private', 'tracker.reject_too_many_announces',
|
'tracker.enabled', 'tracker.private', 'tracker.reject_too_many_announces',
|
||||||
'history.videos.max_age', 'views.videos.remote.max_age', 'views.videos.local_buffer_update_interval', 'views.videos.ip_view_expiration',
|
'history.videos.max_age', 'views.videos.remote.max_age', 'views.videos.local_buffer_update_interval', 'views.videos.ip_view_expiration',
|
||||||
'rates_limit.login.window', 'rates_limit.login.max', 'rates_limit.ask_send_email.window', 'rates_limit.ask_send_email.max',
|
'rates_limit.api.window', 'rates_limit.api.max', 'rates_limit.login.window', 'rates_limit.login.max',
|
||||||
|
'rates_limit.signup.window', 'rates_limit.signup.max', 'rates_limit.ask_send_email.window', 'rates_limit.ask_send_email.max',
|
||||||
|
'rates_limit.receive_client_log.window', 'rates_limit.receive_client_log.max', 'rates_limit.plugins.window', 'rates_limit.plugins.max',
|
||||||
|
'rates_limit.well_known.window', 'rates_limit.well_known.max', 'rates_limit.feeds.window', 'rates_limit.feeds.max',
|
||||||
|
'rates_limit.activity_pub.window', 'rates_limit.activity_pub.max', 'rates_limit.client.window', 'rates_limit.client.max',
|
||||||
'static_files.private_files_require_auth',
|
'static_files.private_files_require_auth',
|
||||||
'object_storage.enabled', 'object_storage.endpoint', 'object_storage.region', 'object_storage.upload_acl.public',
|
'object_storage.enabled', 'object_storage.endpoint', 'object_storage.region', 'object_storage.upload_acl.public',
|
||||||
'object_storage.upload_acl.private', 'object_storage.proxy.proxify_private_files', 'object_storage.credentials.access_key_id',
|
'object_storage.upload_acl.private', 'object_storage.proxy.proxify_private_files', 'object_storage.credentials.access_key_id',
|
||||||
|
|
|
@ -183,6 +183,26 @@ const CONFIG = {
|
||||||
ASK_SEND_EMAIL: {
|
ASK_SEND_EMAIL: {
|
||||||
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.ask_send_email.window')),
|
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.ask_send_email.window')),
|
||||||
MAX: config.get<number>('rates_limit.ask_send_email.max')
|
MAX: config.get<number>('rates_limit.ask_send_email.max')
|
||||||
|
},
|
||||||
|
PLUGINS: {
|
||||||
|
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.plugins.window')),
|
||||||
|
MAX: config.get<number>('rates_limit.plugins.max')
|
||||||
|
},
|
||||||
|
WELL_KNOWN: {
|
||||||
|
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.well_known.window')),
|
||||||
|
MAX: config.get<number>('rates_limit.well_known.max')
|
||||||
|
},
|
||||||
|
FEEDS: {
|
||||||
|
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.feeds.window')),
|
||||||
|
MAX: config.get<number>('rates_limit.feeds.max')
|
||||||
|
},
|
||||||
|
ACTIVITY_PUB: {
|
||||||
|
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.activity_pub.window')),
|
||||||
|
MAX: config.get<number>('rates_limit.activity_pub.max')
|
||||||
|
},
|
||||||
|
CLIENT: {
|
||||||
|
WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.client.window')),
|
||||||
|
MAX: config.get<number>('rates_limit.client.max')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TRUST_PROXY: config.get<string[]>('trust_proxy'),
|
TRUST_PROXY: config.get<string[]>('trust_proxy'),
|
||||||
|
|
|
@ -45,6 +45,11 @@ export const apiRateLimiter = buildRateLimiter({
|
||||||
max: CONFIG.RATES_LIMIT.API.MAX
|
max: CONFIG.RATES_LIMIT.API.MAX
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const activityPubRateLimiter = buildRateLimiter({
|
||||||
|
windowMs: CONFIG.RATES_LIMIT.ACTIVITY_PUB.WINDOW_MS,
|
||||||
|
max: CONFIG.RATES_LIMIT.ACTIVITY_PUB.MAX
|
||||||
|
})
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Private
|
// Private
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -114,7 +114,7 @@ describe('Test video sources API validator', function () {
|
||||||
await server.videos.replaceSourceFile({
|
await server.videos.replaceSourceFile({
|
||||||
fixture: 'video_short_fake.webm',
|
fixture: 'video_short_fake.webm',
|
||||||
videoId,
|
videoId,
|
||||||
expectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422
|
completedExpectedStatus: HttpStatusCode.UNPROCESSABLE_ENTITY_422
|
||||||
})
|
})
|
||||||
|
|
||||||
await server.videos.replaceSourceFile({
|
await server.videos.replaceSourceFile({
|
||||||
|
|
|
@ -23,7 +23,7 @@ describe('Test ActivityPub playlists search', function () {
|
||||||
let command: SearchCommand
|
let command: SearchCommand
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(120000)
|
this.timeout(240000)
|
||||||
|
|
||||||
servers = await createMultipleServers(2)
|
servers = await createMultipleServers(2)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue