mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-04 18:29:27 +02:00
Refactor account/channel manage checks
Use a more robust approach by requiring the caller to choose if it needs to check the actor is local and/or the user can manage it
This commit is contained in:
parent
a1279d7eb5
commit
334ad174a9
25 changed files with 420 additions and 391 deletions
|
@ -140,10 +140,11 @@ describe('Test videos API validator', function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const { total, data } = await server.videos.listMyVideos({ token: userAccessToken, channelId: server.store.channel.id })
|
await server.videos.listMyVideos({
|
||||||
|
token: userAccessToken,
|
||||||
expect(total).to.equal(0)
|
channelId: server.store.channel.id,
|
||||||
expect(data).to.have.lengthOf(0)
|
expectedStatus: HttpStatusCode.FORBIDDEN_403
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,14 +37,13 @@ import {
|
||||||
import {
|
import {
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware,
|
asyncMiddleware,
|
||||||
ensureIsLocalChannel,
|
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
localAccountValidator,
|
videoChannelsHandleValidatorFactory,
|
||||||
videoChannelsNameWithHostValidator,
|
|
||||||
videosCustomGetValidator,
|
videosCustomGetValidator,
|
||||||
videosShareValidator
|
videosShareValidator
|
||||||
} from '../../middlewares/index.js'
|
} from '../../middlewares/index.js'
|
||||||
import {
|
import {
|
||||||
|
accountHandleGetValidatorFactory,
|
||||||
getAccountVideoRateValidatorFactory,
|
getAccountVideoRateValidatorFactory,
|
||||||
getVideoLocalViewerValidator,
|
getVideoLocalViewerValidator,
|
||||||
videoCommentGetValidator
|
videoCommentGetValidator
|
||||||
|
@ -68,35 +67,40 @@ 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,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
asyncMiddleware(accountController)
|
asyncMiddleware(accountController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/followers',
|
activityPubClientRouter.get(
|
||||||
|
'/accounts?/:name/followers',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
asyncMiddleware(accountFollowersController)
|
asyncMiddleware(accountFollowersController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/following',
|
activityPubClientRouter.get(
|
||||||
|
'/accounts?/:name/following',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
asyncMiddleware(accountFollowingController)
|
asyncMiddleware(accountFollowingController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/playlists',
|
activityPubClientRouter.get(
|
||||||
|
'/accounts?/:name/playlists',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
asyncMiddleware(accountPlaylistsController)
|
asyncMiddleware(accountPlaylistsController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/accounts?/:name/likes/:videoId',
|
activityPubClientRouter.get(
|
||||||
|
'/accounts?/:name/likes/:videoId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
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,
|
activityPubRateLimiter,
|
||||||
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
cacheRoute(ROUTE_CACHE_LIFETIME.ACTIVITY_PUB.VIDEOS),
|
||||||
|
@ -106,19 +110,22 @@ activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId',
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
activityPubClientRouter.get('/videos/watch/:id/comments',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/watch/:id/comments',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
||||||
asyncMiddleware(videoCommentsController)
|
asyncMiddleware(videoCommentsController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/approve-reply',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/watch/:videoId/comments/:commentId/approve-reply',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoCommentGetValidator),
|
asyncMiddleware(videoCommentGetValidator),
|
||||||
asyncMiddleware(videoCommentApprovedController)
|
asyncMiddleware(videoCommentApprovedController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/watch/:videoId/comments/:commentId/activity',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoCommentGetValidator),
|
asyncMiddleware(videoCommentGetValidator),
|
||||||
|
@ -142,31 +149,36 @@ activityPubClientRouter.get(
|
||||||
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,
|
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,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
||||||
asyncMiddleware(videoAnnouncesController)
|
asyncMiddleware(videoAnnouncesController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/announces/:actorId',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/watch/:id/announces/:actorId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosShareValidator),
|
asyncMiddleware(videosShareValidator),
|
||||||
asyncMiddleware(videoAnnounceController)
|
asyncMiddleware(videoAnnounceController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/likes',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/watch/:id/likes',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
||||||
asyncMiddleware(videoLikesController)
|
asyncMiddleware(videoLikesController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/dislikes',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/watch/:id/dislikes',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
asyncMiddleware(videosCustomGetValidator('only-video-and-blacklist')),
|
||||||
|
@ -183,7 +195,8 @@ InternalEventEmitter.Instance.on('chapters-updated', ({ video }) => {
|
||||||
chaptersApiCache.clearGroupSafe(buildAPVideoChaptersGroupsCache({ videoId: video.uuid }))
|
chaptersApiCache.clearGroupSafe(buildAPVideoChaptersGroupsCache({ videoId: video.uuid }))
|
||||||
})
|
})
|
||||||
|
|
||||||
activityPubClientRouter.get('/videos/watch/:id/chapters',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/watch/:id/chapters',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
apVideoChaptersSetCacheKey,
|
apVideoChaptersSetCacheKey,
|
||||||
|
@ -198,33 +211,33 @@ 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,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
asyncMiddleware(videoChannelController)
|
asyncMiddleware(videoChannelController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-channels/:nameWithHost/followers',
|
activityPubClientRouter.get(
|
||||||
|
'/video-channels/:nameWithHost/followers',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
asyncMiddleware(videoChannelFollowersController)
|
asyncMiddleware(videoChannelFollowersController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-channels/:nameWithHost/following',
|
activityPubClientRouter.get(
|
||||||
|
'/video-channels/:nameWithHost/following',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
asyncMiddleware(videoChannelFollowingController)
|
asyncMiddleware(videoChannelFollowingController)
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/video-channels/:nameWithHost/playlists',
|
activityPubClientRouter.get(
|
||||||
|
'/video-channels/:nameWithHost/playlists',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
asyncMiddleware(videoChannelPlaylistsController)
|
asyncMiddleware(videoChannelPlaylistsController)
|
||||||
)
|
)
|
||||||
|
|
||||||
activityPubClientRouter.get('/redundancy/streaming-playlists/:streamingPlaylistType/:videoId',
|
activityPubClientRouter.get(
|
||||||
|
'/redundancy/streaming-playlists/:streamingPlaylistType/:videoId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoPlaylistRedundancyGetValidator),
|
asyncMiddleware(videoPlaylistRedundancyGetValidator),
|
||||||
|
@ -238,14 +251,16 @@ activityPubClientRouter.get(
|
||||||
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,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(videoPlaylistElementAPGetValidator),
|
asyncMiddleware(videoPlaylistElementAPGetValidator),
|
||||||
asyncMiddleware(videoPlaylistElementController)
|
asyncMiddleware(videoPlaylistElementController)
|
||||||
)
|
)
|
||||||
|
|
||||||
activityPubClientRouter.get('/videos/local-viewer/:localViewerId',
|
activityPubClientRouter.get(
|
||||||
|
'/videos/local-viewer/:localViewerId',
|
||||||
executeIfActivityPub,
|
executeIfActivityPub,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware(getVideoLocalViewerValidator),
|
asyncMiddleware(getVideoLocalViewerValidator),
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import express from 'express'
|
|
||||||
import { Activity, ActivityPubCollection, ActivityPubOrderedCollection, HttpStatusCode, RootActivity } from '@peertube/peertube-models'
|
import { Activity, ActivityPubCollection, ActivityPubOrderedCollection, HttpStatusCode, RootActivity } from '@peertube/peertube-models'
|
||||||
import { InboxManager } from '@server/lib/activitypub/inbox-manager.js'
|
import { InboxManager } from '@server/lib/activitypub/inbox-manager.js'
|
||||||
|
import express from 'express'
|
||||||
import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity.js'
|
import { isActivityValid } from '../../helpers/custom-validators/activitypub/activity.js'
|
||||||
import { logger } from '../../helpers/logger.js'
|
import { logger } from '../../helpers/logger.js'
|
||||||
import {
|
import {
|
||||||
|
accountHandleGetValidatorFactory,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware,
|
asyncMiddleware,
|
||||||
checkSignature,
|
checkSignature,
|
||||||
ensureIsLocalChannel,
|
|
||||||
localAccountValidator,
|
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
videoChannelsNameWithHostValidator
|
videoChannelsHandleValidatorFactory
|
||||||
} from '../../middlewares/index.js'
|
} from '../../middlewares/index.js'
|
||||||
import { activityPubValidator } from '../../middlewares/validators/activitypub/activity.js'
|
import { activityPubValidator } from '../../middlewares/validators/activitypub/activity.js'
|
||||||
|
|
||||||
const inboxRouter = express.Router()
|
const inboxRouter = express.Router()
|
||||||
|
|
||||||
inboxRouter.post('/inbox',
|
inboxRouter.post(
|
||||||
|
'/inbox',
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
asyncMiddleware(checkSignature),
|
asyncMiddleware(checkSignature),
|
||||||
|
@ -24,21 +24,22 @@ inboxRouter.post('/inbox',
|
||||||
inboxController
|
inboxController
|
||||||
)
|
)
|
||||||
|
|
||||||
inboxRouter.post('/accounts/:name/inbox',
|
inboxRouter.post(
|
||||||
|
'/accounts/:name/inbox',
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
asyncMiddleware(checkSignature),
|
asyncMiddleware(checkSignature),
|
||||||
asyncMiddleware(localAccountValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
asyncMiddleware(activityPubValidator),
|
asyncMiddleware(activityPubValidator),
|
||||||
inboxController
|
inboxController
|
||||||
)
|
)
|
||||||
|
|
||||||
inboxRouter.post('/video-channels/:nameWithHost/inbox',
|
inboxRouter.post(
|
||||||
|
'/video-channels/:nameWithHost/inbox',
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
signatureValidator,
|
signatureValidator,
|
||||||
asyncMiddleware(checkSignature),
|
asyncMiddleware(checkSignature),
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
asyncMiddleware(activityPubValidator),
|
asyncMiddleware(activityPubValidator),
|
||||||
inboxController
|
inboxController
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,18 +1,17 @@
|
||||||
import express from 'express'
|
|
||||||
import { Activity, VideoPrivacy } from '@peertube/peertube-models'
|
import { Activity, VideoPrivacy } from '@peertube/peertube-models'
|
||||||
import { activityPubContextify } from '@server/helpers/activity-pub-utils.js'
|
import { activityPubContextify } from '@server/helpers/activity-pub-utils.js'
|
||||||
import { activityPubCollectionPagination } from '@server/lib/activitypub/collection.js'
|
import { activityPubCollectionPagination } from '@server/lib/activitypub/collection.js'
|
||||||
import { getContextFilter } from '@server/lib/activitypub/context.js'
|
import { getContextFilter } from '@server/lib/activitypub/context.js'
|
||||||
import { MActorLight } from '@server/types/models/index.js'
|
import { MActorLight } from '@server/types/models/index.js'
|
||||||
|
import express from 'express'
|
||||||
import { logger } from '../../helpers/logger.js'
|
import { logger } from '../../helpers/logger.js'
|
||||||
import { buildAudience } from '../../lib/activitypub/audience.js'
|
import { buildAudience } from '../../lib/activitypub/audience.js'
|
||||||
import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send/index.js'
|
import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send/index.js'
|
||||||
import {
|
import {
|
||||||
|
accountHandleGetValidatorFactory,
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
asyncMiddleware,
|
asyncMiddleware,
|
||||||
ensureIsLocalChannel,
|
videoChannelsHandleValidatorFactory
|
||||||
localAccountValidator,
|
|
||||||
videoChannelsNameWithHostValidator
|
|
||||||
} from '../../middlewares/index.js'
|
} from '../../middlewares/index.js'
|
||||||
import { apPaginationValidator } from '../../middlewares/validators/activitypub/index.js'
|
import { apPaginationValidator } from '../../middlewares/validators/activitypub/index.js'
|
||||||
import { VideoModel } from '../../models/video/video.js'
|
import { VideoModel } from '../../models/video/video.js'
|
||||||
|
@ -20,18 +19,19 @@ import { activityPubResponse } from './utils.js'
|
||||||
|
|
||||||
const outboxRouter = express.Router()
|
const outboxRouter = express.Router()
|
||||||
|
|
||||||
outboxRouter.get('/accounts/:name/outbox',
|
outboxRouter.get(
|
||||||
|
'/accounts/:name/outbox',
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
apPaginationValidator,
|
apPaginationValidator,
|
||||||
localAccountValidator,
|
accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: false }),
|
||||||
asyncMiddleware(outboxController)
|
asyncMiddleware(outboxController)
|
||||||
)
|
)
|
||||||
|
|
||||||
outboxRouter.get('/video-channels/:nameWithHost/outbox',
|
outboxRouter.get(
|
||||||
|
'/video-channels/:nameWithHost/outbox',
|
||||||
activityPubRateLimiter,
|
activityPubRateLimiter,
|
||||||
apPaginationValidator,
|
apPaginationValidator,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: false })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
asyncMiddleware(outboxController)
|
asyncMiddleware(outboxController)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import express from 'express'
|
|
||||||
import { pickCommonVideoQuery } from '@server/helpers/query.js'
|
import { pickCommonVideoQuery } from '@server/helpers/query.js'
|
||||||
import { ActorFollowModel } from '@server/models/actor/actor-follow.js'
|
import { ActorFollowModel } from '@server/models/actor/actor-follow.js'
|
||||||
import { getServerActor } from '@server/models/application/application.js'
|
import { getServerActor } from '@server/models/application/application.js'
|
||||||
import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync.js'
|
import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync.js'
|
||||||
|
import express from 'express'
|
||||||
import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils.js'
|
import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils.js'
|
||||||
import { getFormattedObjects } from '../../helpers/utils.js'
|
import { getFormattedObjects } from '../../helpers/utils.js'
|
||||||
import { JobQueue } from '../../lib/job-queue/index.js'
|
import { JobQueue } from '../../lib/job-queue/index.js'
|
||||||
|
@ -22,29 +22,28 @@ import {
|
||||||
videoRatingValidator
|
videoRatingValidator
|
||||||
} from '../../middlewares/index.js'
|
} from '../../middlewares/index.js'
|
||||||
import {
|
import {
|
||||||
accountNameWithHostGetValidator,
|
accountHandleGetValidatorFactory,
|
||||||
accountsFollowersSortValidator,
|
accountsFollowersSortValidator,
|
||||||
accountsSortValidator,
|
accountsSortValidator,
|
||||||
ensureAuthUserOwnsAccountValidator,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
videoChannelsSortValidator,
|
videoChannelsSortValidator,
|
||||||
videoChannelStatsValidator,
|
videoChannelStatsValidator,
|
||||||
videoChannelSyncsSortValidator,
|
videoChannelSyncsSortValidator,
|
||||||
videosSortValidator
|
videosSortValidator
|
||||||
} from '../../middlewares/validators/index.js'
|
} from '../../middlewares/validators/index.js'
|
||||||
import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists.js'
|
import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists.js'
|
||||||
import { AccountModel } from '../../models/account/account.js'
|
|
||||||
import { AccountVideoRateModel } from '../../models/account/account-video-rate.js'
|
import { AccountVideoRateModel } from '../../models/account/account-video-rate.js'
|
||||||
|
import { AccountModel } from '../../models/account/account.js'
|
||||||
import { guessAdditionalAttributesFromQuery } from '../../models/video/formatter/index.js'
|
import { guessAdditionalAttributesFromQuery } from '../../models/video/formatter/index.js'
|
||||||
import { VideoModel } from '../../models/video/video.js'
|
|
||||||
import { VideoChannelModel } from '../../models/video/video-channel.js'
|
import { VideoChannelModel } from '../../models/video/video-channel.js'
|
||||||
import { VideoPlaylistModel } from '../../models/video/video-playlist.js'
|
import { VideoPlaylistModel } from '../../models/video/video-playlist.js'
|
||||||
|
import { VideoModel } from '../../models/video/video.js'
|
||||||
|
|
||||||
const accountsRouter = express.Router()
|
const accountsRouter = express.Router()
|
||||||
|
|
||||||
accountsRouter.use(apiRateLimiter)
|
accountsRouter.use(apiRateLimiter)
|
||||||
|
|
||||||
accountsRouter.get('/',
|
accountsRouter.get(
|
||||||
|
'/',
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
accountsSortValidator,
|
accountsSortValidator,
|
||||||
setDefaultSort,
|
setDefaultSort,
|
||||||
|
@ -52,13 +51,15 @@ accountsRouter.get('/',
|
||||||
asyncMiddleware(listAccounts)
|
asyncMiddleware(listAccounts)
|
||||||
)
|
)
|
||||||
|
|
||||||
accountsRouter.get('/:accountName',
|
accountsRouter.get(
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
'/:accountName',
|
||||||
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
getAccount
|
getAccount
|
||||||
)
|
)
|
||||||
|
|
||||||
accountsRouter.get('/:accountName/videos',
|
accountsRouter.get(
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
'/:accountName/videos',
|
||||||
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videosSortValidator,
|
videosSortValidator,
|
||||||
setDefaultVideosSort,
|
setDefaultVideosSort,
|
||||||
|
@ -68,8 +69,9 @@ accountsRouter.get('/:accountName/videos',
|
||||||
asyncMiddleware(listAccountVideos)
|
asyncMiddleware(listAccountVideos)
|
||||||
)
|
)
|
||||||
|
|
||||||
accountsRouter.get('/:accountName/video-channels',
|
accountsRouter.get(
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
'/:accountName/video-channels',
|
||||||
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
videoChannelStatsValidator,
|
videoChannelStatsValidator,
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videoChannelsSortValidator,
|
videoChannelsSortValidator,
|
||||||
|
@ -78,20 +80,10 @@ accountsRouter.get('/:accountName/video-channels',
|
||||||
asyncMiddleware(listAccountChannels)
|
asyncMiddleware(listAccountChannels)
|
||||||
)
|
)
|
||||||
|
|
||||||
accountsRouter.get('/:accountName/video-channel-syncs',
|
accountsRouter.get(
|
||||||
authenticate,
|
'/:accountName/video-playlists',
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
paginationValidator,
|
|
||||||
videoChannelSyncsSortValidator,
|
|
||||||
setDefaultSort,
|
|
||||||
setDefaultPagination,
|
|
||||||
asyncMiddleware(listAccountChannelsSync)
|
|
||||||
)
|
|
||||||
|
|
||||||
accountsRouter.get('/:accountName/video-playlists',
|
|
||||||
optionalAuthenticate,
|
optionalAuthenticate,
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videoPlaylistsSortValidator,
|
videoPlaylistsSortValidator,
|
||||||
setDefaultSort,
|
setDefaultSort,
|
||||||
|
@ -101,10 +93,21 @@ accountsRouter.get('/:accountName/video-playlists',
|
||||||
asyncMiddleware(listAccountPlaylists)
|
asyncMiddleware(listAccountPlaylists)
|
||||||
)
|
)
|
||||||
|
|
||||||
accountsRouter.get('/:accountName/ratings',
|
accountsRouter.get(
|
||||||
|
'/:accountName/video-channel-syncs',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureAuthUserOwnsAccountValidator,
|
paginationValidator,
|
||||||
|
videoChannelSyncsSortValidator,
|
||||||
|
setDefaultSort,
|
||||||
|
setDefaultPagination,
|
||||||
|
asyncMiddleware(listAccountChannelsSync)
|
||||||
|
)
|
||||||
|
|
||||||
|
accountsRouter.get(
|
||||||
|
'/:accountName/ratings',
|
||||||
|
authenticate,
|
||||||
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videoRatesSortValidator,
|
videoRatesSortValidator,
|
||||||
setDefaultSort,
|
setDefaultSort,
|
||||||
|
@ -113,10 +116,10 @@ accountsRouter.get('/:accountName/ratings',
|
||||||
asyncMiddleware(listAccountRatings)
|
asyncMiddleware(listAccountRatings)
|
||||||
)
|
)
|
||||||
|
|
||||||
accountsRouter.get('/:accountName/followers',
|
accountsRouter.get(
|
||||||
|
'/:accountName/followers',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureAuthUserOwnsAccountValidator,
|
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
accountsFollowersSortValidator,
|
accountsFollowersSortValidator,
|
||||||
setDefaultSort,
|
setDefaultSort,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import express from 'express'
|
import { pick } from '@peertube/peertube-core-utils'
|
||||||
|
import { HttpStatusCode, UserCreate, UserCreateResult, UserRight, UserUpdate } from '@peertube/peertube-models'
|
||||||
import { tokensRouter } from '@server/controllers/api/users/token.js'
|
import { tokensRouter } from '@server/controllers/api/users/token.js'
|
||||||
import { Hooks } from '@server/lib/plugins/hooks.js'
|
import { Hooks } from '@server/lib/plugins/hooks.js'
|
||||||
import { OAuthTokenModel } from '@server/models/oauth/oauth-token.js'
|
import { OAuthTokenModel } from '@server/models/oauth/oauth-token.js'
|
||||||
import { MUserAccountDefault } from '@server/types/models/index.js'
|
import { MUserAccountDefault } from '@server/types/models/index.js'
|
||||||
import { pick } from '@peertube/peertube-core-utils'
|
import express from 'express'
|
||||||
import { HttpStatusCode, UserCreate, UserCreateResult, UserRight, UserUpdate } from '@peertube/peertube-models'
|
|
||||||
import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger.js'
|
import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger.js'
|
||||||
import { logger, loggerTagsFactory } from '../../../helpers/logger.js'
|
import { logger, loggerTagsFactory } from '../../../helpers/logger.js'
|
||||||
import { generateRandomString, getFormattedObjects } from '../../../helpers/utils.js'
|
import { generateRandomString, getFormattedObjects } from '../../../helpers/utils.js'
|
||||||
|
@ -31,9 +31,8 @@ import {
|
||||||
usersUpdateValidator
|
usersUpdateValidator
|
||||||
} from '../../../middlewares/index.js'
|
} from '../../../middlewares/index.js'
|
||||||
import {
|
import {
|
||||||
ensureCanModerateUser,
|
|
||||||
usersAskResetPasswordValidator,
|
usersAskResetPasswordValidator,
|
||||||
usersBlockingValidator,
|
usersBlockToggleValidator,
|
||||||
usersResetPasswordValidator
|
usersResetPasswordValidator
|
||||||
} from '../../../middlewares/validators/index.js'
|
} from '../../../middlewares/validators/index.js'
|
||||||
import { UserModel } from '../../../models/user/user.js'
|
import { UserModel } from '../../../models/user/user.js'
|
||||||
|
@ -71,12 +70,10 @@ usersRouter.use('/', myVideoPlaylistsRouter)
|
||||||
usersRouter.use('/', myAbusesRouter)
|
usersRouter.use('/', myAbusesRouter)
|
||||||
usersRouter.use('/', meRouter)
|
usersRouter.use('/', meRouter)
|
||||||
|
|
||||||
usersRouter.get('/autocomplete',
|
usersRouter.get('/autocomplete', userAutocompleteValidator, asyncMiddleware(autocompleteUsers))
|
||||||
userAutocompleteValidator,
|
|
||||||
asyncMiddleware(autocompleteUsers)
|
|
||||||
)
|
|
||||||
|
|
||||||
usersRouter.get('/',
|
usersRouter.get(
|
||||||
|
'/',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
ensureUserHasRight(UserRight.MANAGE_USERS),
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
|
@ -87,60 +84,50 @@ usersRouter.get('/',
|
||||||
asyncMiddleware(listUsers)
|
asyncMiddleware(listUsers)
|
||||||
)
|
)
|
||||||
|
|
||||||
usersRouter.post('/:id/block',
|
usersRouter.post(
|
||||||
|
'/:id/block',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
ensureUserHasRight(UserRight.MANAGE_USERS),
|
||||||
asyncMiddleware(usersBlockingValidator),
|
asyncMiddleware(usersBlockToggleValidator),
|
||||||
ensureCanModerateUser,
|
|
||||||
asyncMiddleware(blockUser)
|
asyncMiddleware(blockUser)
|
||||||
)
|
)
|
||||||
usersRouter.post('/:id/unblock',
|
usersRouter.post(
|
||||||
|
'/:id/unblock',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
ensureUserHasRight(UserRight.MANAGE_USERS),
|
||||||
asyncMiddleware(usersBlockingValidator),
|
asyncMiddleware(usersBlockToggleValidator),
|
||||||
ensureCanModerateUser,
|
|
||||||
asyncMiddleware(unblockUser)
|
asyncMiddleware(unblockUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
usersRouter.get('/:id',
|
usersRouter.get('/:id', authenticate, ensureUserHasRight(UserRight.MANAGE_USERS), asyncMiddleware(usersGetValidator), getUser)
|
||||||
authenticate,
|
|
||||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
|
||||||
asyncMiddleware(usersGetValidator),
|
|
||||||
getUser
|
|
||||||
)
|
|
||||||
|
|
||||||
usersRouter.post('/',
|
usersRouter.post(
|
||||||
|
'/',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
ensureUserHasRight(UserRight.MANAGE_USERS),
|
||||||
asyncMiddleware(usersAddValidator),
|
asyncMiddleware(usersAddValidator),
|
||||||
asyncRetryTransactionMiddleware(createUser)
|
asyncRetryTransactionMiddleware(createUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
usersRouter.put('/:id',
|
usersRouter.put(
|
||||||
|
'/:id',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
ensureUserHasRight(UserRight.MANAGE_USERS),
|
||||||
asyncMiddleware(usersUpdateValidator),
|
asyncMiddleware(usersUpdateValidator),
|
||||||
ensureCanModerateUser,
|
|
||||||
asyncMiddleware(updateUser)
|
asyncMiddleware(updateUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
usersRouter.delete('/:id',
|
usersRouter.delete(
|
||||||
|
'/:id',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureUserHasRight(UserRight.MANAGE_USERS),
|
ensureUserHasRight(UserRight.MANAGE_USERS),
|
||||||
asyncMiddleware(usersRemoveValidator),
|
asyncMiddleware(usersRemoveValidator),
|
||||||
ensureCanModerateUser,
|
|
||||||
asyncMiddleware(removeUser)
|
asyncMiddleware(removeUser)
|
||||||
)
|
)
|
||||||
|
|
||||||
usersRouter.post('/ask-reset-password',
|
usersRouter.post('/ask-reset-password', asyncMiddleware(usersAskResetPasswordValidator), asyncMiddleware(askResetUserPassword))
|
||||||
asyncMiddleware(usersAskResetPasswordValidator),
|
|
||||||
asyncMiddleware(askResetUserPassword)
|
|
||||||
)
|
|
||||||
|
|
||||||
usersRouter.post('/:id/reset-password',
|
usersRouter.post('/:id/reset-password', asyncMiddleware(usersResetPasswordValidator), asyncMiddleware(resetUserPassword))
|
||||||
asyncMiddleware(usersResetPasswordValidator),
|
|
||||||
asyncMiddleware(resetUserPassword)
|
|
||||||
)
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import express from 'express'
|
import { HttpStatusCode, VideoChannelSyncState } from '@peertube/peertube-models'
|
||||||
import { auditLoggerFactory, getAuditIdFromRes, VideoChannelSyncAuditView } from '@server/helpers/audit-logger.js'
|
import { auditLoggerFactory, getAuditIdFromRes, VideoChannelSyncAuditView } from '@server/helpers/audit-logger.js'
|
||||||
import { logger } from '@server/helpers/logger.js'
|
import { logger } from '@server/helpers/logger.js'
|
||||||
import {
|
import {
|
||||||
|
@ -6,32 +6,31 @@ import {
|
||||||
asyncMiddleware,
|
asyncMiddleware,
|
||||||
asyncRetryTransactionMiddleware,
|
asyncRetryTransactionMiddleware,
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
ensureSyncExists,
|
ensureSyncExists,
|
||||||
ensureSyncIsEnabled,
|
ensureSyncIsEnabled,
|
||||||
videoChannelSyncValidator
|
videoChannelSyncValidator
|
||||||
} from '@server/middlewares/index.js'
|
} from '@server/middlewares/index.js'
|
||||||
import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync.js'
|
import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync.js'
|
||||||
import { MChannelSyncFormattable } from '@server/types/models/index.js'
|
import { MChannelSyncFormattable } from '@server/types/models/index.js'
|
||||||
import { HttpStatusCode, VideoChannelSyncState } from '@peertube/peertube-models'
|
import express from 'express'
|
||||||
|
|
||||||
const videoChannelSyncRouter = express.Router()
|
const videoChannelSyncRouter = express.Router()
|
||||||
const auditLogger = auditLoggerFactory('channel-syncs')
|
const auditLogger = auditLoggerFactory('channel-syncs')
|
||||||
|
|
||||||
videoChannelSyncRouter.use(apiRateLimiter)
|
videoChannelSyncRouter.use(apiRateLimiter)
|
||||||
|
|
||||||
videoChannelSyncRouter.post('/',
|
videoChannelSyncRouter.post(
|
||||||
|
'/',
|
||||||
authenticate,
|
authenticate,
|
||||||
ensureSyncIsEnabled,
|
ensureSyncIsEnabled,
|
||||||
asyncMiddleware(videoChannelSyncValidator),
|
asyncMiddleware(videoChannelSyncValidator),
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
asyncRetryTransactionMiddleware(createVideoChannelSync)
|
asyncRetryTransactionMiddleware(createVideoChannelSync)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelSyncRouter.delete('/:id',
|
videoChannelSyncRouter.delete(
|
||||||
|
'/:id',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(ensureSyncExists),
|
asyncMiddleware(ensureSyncExists),
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
asyncRetryTransactionMiddleware(removeVideoChannelSync)
|
asyncRetryTransactionMiddleware(removeVideoChannelSync)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import express from 'express'
|
|
||||||
import {
|
import {
|
||||||
ActorImageType,
|
ActorImageType,
|
||||||
HttpStatusCode,
|
HttpStatusCode,
|
||||||
|
@ -11,6 +10,7 @@ import { Hooks } from '@server/lib/plugins/hooks.js'
|
||||||
import { ActorFollowModel } from '@server/models/actor/actor-follow.js'
|
import { ActorFollowModel } from '@server/models/actor/actor-follow.js'
|
||||||
import { getServerActor } from '@server/models/application/application.js'
|
import { getServerActor } from '@server/models/application/application.js'
|
||||||
import { MChannelBannerAccountDefault } from '@server/types/models/index.js'
|
import { MChannelBannerAccountDefault } from '@server/types/models/index.js'
|
||||||
|
import express from 'express'
|
||||||
import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger.js'
|
import { auditLoggerFactory, getAuditIdFromRes, VideoChannelAuditView } from '../../helpers/audit-logger.js'
|
||||||
import { resetSequelizeInstance } from '../../helpers/database-utils.js'
|
import { resetSequelizeInstance } from '../../helpers/database-utils.js'
|
||||||
import { buildNSFWFilter, createReqFiles, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils.js'
|
import { buildNSFWFilter, createReqFiles, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils.js'
|
||||||
|
@ -28,7 +28,6 @@ import {
|
||||||
asyncRetryTransactionMiddleware,
|
asyncRetryTransactionMiddleware,
|
||||||
authenticate,
|
authenticate,
|
||||||
commonVideosFiltersValidator,
|
commonVideosFiltersValidator,
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
optionalAuthenticate,
|
optionalAuthenticate,
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
setDefaultPagination,
|
setDefaultPagination,
|
||||||
|
@ -43,11 +42,10 @@ import {
|
||||||
import { updateAvatarValidator, updateBannerValidator } from '../../middlewares/validators/actor-image.js'
|
import { updateAvatarValidator, updateBannerValidator } from '../../middlewares/validators/actor-image.js'
|
||||||
import {
|
import {
|
||||||
ensureChannelOwnerCanUpload,
|
ensureChannelOwnerCanUpload,
|
||||||
ensureIsLocalChannel,
|
|
||||||
videoChannelImportVideosValidator,
|
videoChannelImportVideosValidator,
|
||||||
videoChannelsFollowersSortValidator,
|
videoChannelsFollowersSortValidator,
|
||||||
|
videoChannelsHandleValidatorFactory,
|
||||||
videoChannelsListValidator,
|
videoChannelsListValidator,
|
||||||
videoChannelsNameWithHostValidator,
|
|
||||||
videosSortValidator
|
videosSortValidator
|
||||||
} from '../../middlewares/validators/index.js'
|
} from '../../middlewares/validators/index.js'
|
||||||
import { commonVideoPlaylistFiltersValidator } from '../../middlewares/validators/videos/video-playlists.js'
|
import { commonVideoPlaylistFiltersValidator } from '../../middlewares/validators/videos/video-playlists.js'
|
||||||
|
@ -65,7 +63,8 @@ const videoChannelRouter = express.Router()
|
||||||
|
|
||||||
videoChannelRouter.use(apiRateLimiter)
|
videoChannelRouter.use(apiRateLimiter)
|
||||||
|
|
||||||
videoChannelRouter.get('/',
|
videoChannelRouter.get(
|
||||||
|
'/',
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videoChannelsSortValidator,
|
videoChannelsSortValidator,
|
||||||
setDefaultSort,
|
setDefaultSort,
|
||||||
|
@ -74,74 +73,66 @@ videoChannelRouter.get('/',
|
||||||
asyncMiddleware(listVideoChannels)
|
asyncMiddleware(listVideoChannels)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.post('/',
|
videoChannelRouter.post('/', authenticate, asyncMiddleware(videoChannelsAddValidator), asyncRetryTransactionMiddleware(createVideoChannel))
|
||||||
authenticate,
|
|
||||||
asyncMiddleware(videoChannelsAddValidator),
|
|
||||||
asyncRetryTransactionMiddleware(createVideoChannel)
|
|
||||||
)
|
|
||||||
|
|
||||||
videoChannelRouter.post('/:nameWithHost/avatar/pick',
|
videoChannelRouter.post(
|
||||||
|
'/:nameWithHost/avatar/pick',
|
||||||
authenticate,
|
authenticate,
|
||||||
reqAvatarFile,
|
reqAvatarFile,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
updateAvatarValidator,
|
updateAvatarValidator,
|
||||||
asyncMiddleware(updateVideoChannelAvatar)
|
asyncMiddleware(updateVideoChannelAvatar)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.post('/:nameWithHost/banner/pick',
|
videoChannelRouter.post(
|
||||||
|
'/:nameWithHost/banner/pick',
|
||||||
authenticate,
|
authenticate,
|
||||||
reqBannerFile,
|
reqBannerFile,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
updateBannerValidator,
|
updateBannerValidator,
|
||||||
asyncMiddleware(updateVideoChannelBanner)
|
asyncMiddleware(updateVideoChannelBanner)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.delete('/:nameWithHost/avatar',
|
videoChannelRouter.delete(
|
||||||
|
'/:nameWithHost/avatar',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
asyncMiddleware(deleteVideoChannelAvatar)
|
asyncMiddleware(deleteVideoChannelAvatar)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.delete('/:nameWithHost/banner',
|
videoChannelRouter.delete(
|
||||||
|
'/:nameWithHost/banner',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
asyncMiddleware(deleteVideoChannelBanner)
|
asyncMiddleware(deleteVideoChannelBanner)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.put('/:nameWithHost',
|
videoChannelRouter.put(
|
||||||
|
'/:nameWithHost',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
videoChannelsUpdateValidator,
|
videoChannelsUpdateValidator,
|
||||||
asyncRetryTransactionMiddleware(updateVideoChannel)
|
asyncRetryTransactionMiddleware(updateVideoChannel)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.delete('/:nameWithHost',
|
videoChannelRouter.delete(
|
||||||
|
'/:nameWithHost',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
ensureIsLocalChannel,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
asyncMiddleware(videoChannelsRemoveValidator),
|
asyncMiddleware(videoChannelsRemoveValidator),
|
||||||
asyncRetryTransactionMiddleware(removeVideoChannel)
|
asyncRetryTransactionMiddleware(removeVideoChannel)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.get('/:nameWithHost',
|
videoChannelRouter.get(
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
'/:nameWithHost',
|
||||||
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
asyncMiddleware(getVideoChannel)
|
asyncMiddleware(getVideoChannel)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.get('/:nameWithHost/video-playlists',
|
videoChannelRouter.get(
|
||||||
|
'/:nameWithHost/video-playlists',
|
||||||
optionalAuthenticate,
|
optionalAuthenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videoPlaylistsSortValidator,
|
videoPlaylistsSortValidator,
|
||||||
setDefaultSort,
|
setDefaultSort,
|
||||||
|
@ -150,8 +141,9 @@ videoChannelRouter.get('/:nameWithHost/video-playlists',
|
||||||
asyncMiddleware(listVideoChannelPlaylists)
|
asyncMiddleware(listVideoChannelPlaylists)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.get('/:nameWithHost/videos',
|
videoChannelRouter.get(
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
'/:nameWithHost/videos',
|
||||||
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videosSortValidator,
|
videosSortValidator,
|
||||||
setDefaultVideosSort,
|
setDefaultVideosSort,
|
||||||
|
@ -161,10 +153,10 @@ videoChannelRouter.get('/:nameWithHost/videos',
|
||||||
asyncMiddleware(listVideoChannelVideos)
|
asyncMiddleware(listVideoChannelVideos)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.get('/:nameWithHost/followers',
|
videoChannelRouter.get(
|
||||||
|
'/:nameWithHost/followers',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: false, checkManage: true })),
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
paginationValidator,
|
paginationValidator,
|
||||||
videoChannelsFollowersSortValidator,
|
videoChannelsFollowersSortValidator,
|
||||||
setDefaultSort,
|
setDefaultSort,
|
||||||
|
@ -172,12 +164,11 @@ videoChannelRouter.get('/:nameWithHost/followers',
|
||||||
asyncMiddleware(listVideoChannelFollowers)
|
asyncMiddleware(listVideoChannelFollowers)
|
||||||
)
|
)
|
||||||
|
|
||||||
videoChannelRouter.post('/:nameWithHost/import-videos',
|
videoChannelRouter.post(
|
||||||
|
'/:nameWithHost/import-videos',
|
||||||
authenticate,
|
authenticate,
|
||||||
asyncMiddleware(videoChannelsNameWithHostValidator),
|
asyncMiddleware(videoChannelsHandleValidatorFactory({ checkIsLocal: true, checkManage: true })),
|
||||||
asyncMiddleware(videoChannelImportVideosValidator),
|
asyncMiddleware(videoChannelImportVideosValidator),
|
||||||
ensureIsLocalChannel,
|
|
||||||
ensureCanManageChannelOrAccount,
|
|
||||||
asyncMiddleware(ensureChannelOwnerCanUpload),
|
asyncMiddleware(ensureChannelOwnerCanUpload),
|
||||||
asyncMiddleware(importVideosInChannel)
|
asyncMiddleware(importVideosInChannel)
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,19 +4,15 @@ import { escapeHTML, forceNumber } from '@peertube/peertube-core-utils'
|
||||||
import { MChannelSummary } from '@server/types/models/index.js'
|
import { MChannelSummary } from '@server/types/models/index.js'
|
||||||
import { EMBED_SIZE, PREVIEWS_SIZE, THUMBNAILS_SIZE, WEBSERVER } from '../initializers/constants.js'
|
import { EMBED_SIZE, PREVIEWS_SIZE, THUMBNAILS_SIZE, WEBSERVER } from '../initializers/constants.js'
|
||||||
import { apiRateLimiter, asyncMiddleware, oembedValidator } from '../middlewares/index.js'
|
import { apiRateLimiter, asyncMiddleware, oembedValidator } from '../middlewares/index.js'
|
||||||
import { accountNameWithHostGetValidator } from '../middlewares/validators/index.js'
|
import { accountHandleGetValidatorFactory } from '../middlewares/validators/index.js'
|
||||||
|
|
||||||
const servicesRouter = express.Router()
|
const servicesRouter = express.Router()
|
||||||
|
|
||||||
servicesRouter.use('/oembed',
|
servicesRouter.use('/oembed', cors(), apiRateLimiter, asyncMiddleware(oembedValidator), generateOEmbed)
|
||||||
cors(),
|
servicesRouter.use(
|
||||||
|
'/redirect/accounts/:accountName',
|
||||||
apiRateLimiter,
|
apiRateLimiter,
|
||||||
asyncMiddleware(oembedValidator),
|
asyncMiddleware(accountHandleGetValidatorFactory({ checkIsLocal: false, checkManage: false })),
|
||||||
generateOEmbed
|
|
||||||
)
|
|
||||||
servicesRouter.use('/redirect/accounts/:accountName',
|
|
||||||
apiRateLimiter,
|
|
||||||
asyncMiddleware(accountNameWithHostGetValidator),
|
|
||||||
redirectToAccountUrl
|
redirectToAccountUrl
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ export class ActorHtml {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getVideoChannelHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
|
static async getVideoChannelHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
|
||||||
const videoChannel = await VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost)
|
const videoChannel = await VideoChannelModel.loadByHandleAndPopulateAccount(nameWithHost)
|
||||||
|
|
||||||
return this.getAccountOrChannelHTMLPage({
|
return this.getAccountOrChannelHTMLPage({
|
||||||
loader: () => Promise.resolve(videoChannel),
|
loader: () => Promise.resolve(videoChannel),
|
||||||
|
@ -36,7 +36,7 @@ export class ActorHtml {
|
||||||
static async getActorHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
|
static async getActorHTMLPage (nameWithHost: string, req: express.Request, res: express.Response) {
|
||||||
const [ account, channel ] = await Promise.all([
|
const [ account, channel ] = await Promise.all([
|
||||||
AccountModel.loadByNameWithHost(nameWithHost),
|
AccountModel.loadByNameWithHost(nameWithHost),
|
||||||
VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithHost)
|
VideoChannelModel.loadByHandleAndPopulateAccount(nameWithHost)
|
||||||
])
|
])
|
||||||
|
|
||||||
return this.getAccountOrChannelHTMLPage({
|
return this.getAccountOrChannelHTMLPage({
|
||||||
|
|
|
@ -57,7 +57,7 @@ const abuseReportValidator = [
|
||||||
const body: AbuseCreate = req.body
|
const body: AbuseCreate = req.body
|
||||||
|
|
||||||
if (body.video?.id && !await doesVideoExist(body.video.id, res)) return
|
if (body.video?.id && !await doesVideoExist(body.video.id, res)) return
|
||||||
if (body.account?.id && !await doesAccountIdExist(body.account.id, res)) return
|
if (body.account?.id && !await doesAccountIdExist({ id: body.account.id, res, checkIsLocal: false, checkManage: false })) return
|
||||||
if (body.comment?.id && !await doesCommentIdExist(body.comment.id, res)) return
|
if (body.comment?.id && !await doesCommentIdExist(body.comment.id, res)) return
|
||||||
|
|
||||||
if (!body.video?.id && !body.account?.id && !body.comment?.id) {
|
if (!body.video?.id && !body.account?.id && !body.comment?.id) {
|
||||||
|
|
|
@ -1,35 +1,31 @@
|
||||||
|
import { UserRight } from '@peertube/peertube-models'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { param } from 'express-validator'
|
import { param } from 'express-validator'
|
||||||
import { isAccountNameValid } from '../../helpers/custom-validators/accounts.js'
|
import { areValidationErrors, checkUserCanManageAccount, doesAccountHandleExist } from './shared/index.js'
|
||||||
import { areValidationErrors, doesAccountNameWithHostExist, doesLocalAccountNameExist } from './shared/index.js'
|
|
||||||
|
|
||||||
const localAccountValidator = [
|
export const accountHandleGetValidatorFactory = (options: {
|
||||||
param('name')
|
checkManage: boolean
|
||||||
.custom(isAccountNameValid),
|
checkIsLocal: boolean
|
||||||
|
}) => {
|
||||||
|
const { checkManage, checkIsLocal } = options
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
return [
|
||||||
if (areValidationErrors(req, res)) return
|
param('accountName')
|
||||||
if (!await doesLocalAccountNameExist(req.params.name, res)) return
|
.exists(),
|
||||||
|
|
||||||
return next()
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
}
|
if (areValidationErrors(req, res)) return
|
||||||
]
|
if (!await doesAccountHandleExist({ handle: req.params.accountName, res, checkIsLocal, checkManage })) return
|
||||||
|
|
||||||
const accountNameWithHostGetValidator = [
|
if (options.checkManage) {
|
||||||
param('accountName')
|
const user = res.locals.oauth.token.User
|
||||||
.exists(),
|
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
if (!checkUserCanManageAccount({ account: res.locals.account, user, res, specialRight: UserRight.MANAGE_USERS })) {
|
||||||
if (areValidationErrors(req, res)) return
|
return false
|
||||||
if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export {
|
|
||||||
localAccountValidator,
|
|
||||||
accountNameWithHostGetValidator
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ import { isStringArray } from '@server/helpers/custom-validators/search.js'
|
||||||
import { AutomaticTagger } from '@server/lib/automatic-tags/automatic-tagger.js'
|
import { AutomaticTagger } from '@server/lib/automatic-tags/automatic-tagger.js'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { body, param } from 'express-validator'
|
import { body, param } from 'express-validator'
|
||||||
import { doesAccountNameWithHostExist } from './shared/accounts.js'
|
import { doesAccountHandleExist } from './shared/accounts.js'
|
||||||
import { checkUserCanManageAccount } from './shared/users.js'
|
|
||||||
import { areValidationErrors } from './shared/utils.js'
|
import { areValidationErrors } from './shared/utils.js'
|
||||||
|
|
||||||
export const manageAccountAutomaticTagsValidator = [
|
export const manageAccountAutomaticTagsValidator = [
|
||||||
|
@ -13,8 +12,7 @@ export const manageAccountAutomaticTagsValidator = [
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return
|
if (!await doesAccountHandleExist({ handle: req.params.accountName, res, checkIsLocal: true, checkManage: true })) return
|
||||||
if (!checkUserCanManageAccount({ user: res.locals.oauth.token.User, account: res.locals.account, specialRight: null, res })) return
|
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { WEBSERVER } from '../../initializers/constants.js'
|
||||||
import { AccountBlocklistModel } from '../../models/account/account-blocklist.js'
|
import { AccountBlocklistModel } from '../../models/account/account-blocklist.js'
|
||||||
import { ServerBlocklistModel } from '../../models/server/server-blocklist.js'
|
import { ServerBlocklistModel } from '../../models/server/server-blocklist.js'
|
||||||
import { ServerModel } from '../../models/server/server.js'
|
import { ServerModel } from '../../models/server/server.js'
|
||||||
import { areValidationErrors, doesAccountNameWithHostExist } from './shared/index.js'
|
import { areValidationErrors, doesAccountHandleExist } from './shared/index.js'
|
||||||
|
|
||||||
const blockAccountValidator = [
|
const blockAccountValidator = [
|
||||||
body('accountName')
|
body('accountName')
|
||||||
|
@ -17,7 +17,7 @@ const blockAccountValidator = [
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await doesAccountNameWithHostExist(req.body.accountName, res)) return
|
if (!await doesAccountHandleExist({ handle: req.body.accountName, res, checkIsLocal: false, checkManage: false })) return
|
||||||
|
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
const accountToBlock = res.locals.account
|
const accountToBlock = res.locals.account
|
||||||
|
@ -40,7 +40,7 @@ const unblockAccountByAccountValidator = [
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return
|
if (!await doesAccountHandleExist({ handle: req.params.accountName, res, checkIsLocal: false, checkManage: false })) return
|
||||||
|
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
const targetAccount = res.locals.account
|
const targetAccount = res.locals.account
|
||||||
|
@ -56,7 +56,7 @@ const unblockAccountByServerValidator = [
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return
|
if (!await doesAccountHandleExist({ handle: req.params.accountName, res, checkIsLocal: false, checkManage: false })) return
|
||||||
|
|
||||||
const serverActor = await getServerActor()
|
const serverActor = await getServerActor()
|
||||||
const targetAccount = res.locals.account
|
const targetAccount = res.locals.account
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import express from 'express'
|
|
||||||
import { body } from 'express-validator'
|
|
||||||
import { BulkRemoveCommentsOfBody, HttpStatusCode, UserRight } from '@peertube/peertube-models'
|
import { BulkRemoveCommentsOfBody, HttpStatusCode, UserRight } from '@peertube/peertube-models'
|
||||||
import { isBulkRemoveCommentsOfScopeValid } from '@server/helpers/custom-validators/bulk.js'
|
import { isBulkRemoveCommentsOfScopeValid } from '@server/helpers/custom-validators/bulk.js'
|
||||||
import { areValidationErrors, doesAccountNameWithHostExist } from './shared/index.js'
|
import express from 'express'
|
||||||
|
import { body } from 'express-validator'
|
||||||
|
import { areValidationErrors, doesAccountHandleExist } from './shared/index.js'
|
||||||
|
|
||||||
const bulkRemoveCommentsOfValidator = [
|
export const bulkRemoveCommentsOfValidator = [
|
||||||
body('accountName')
|
body('accountName')
|
||||||
.exists(),
|
.exists(),
|
||||||
body('scope')
|
body('scope')
|
||||||
|
@ -12,7 +12,7 @@ const bulkRemoveCommentsOfValidator = [
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await doesAccountNameWithHostExist(req.body.accountName, res)) return
|
if (!await doesAccountHandleExist({ handle: req.body.accountName, res, checkIsLocal: false, checkManage: false })) return
|
||||||
|
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
const body = req.body as BulkRemoveCommentsOfBody
|
const body = req.body as BulkRemoveCommentsOfBody
|
||||||
|
@ -27,11 +27,3 @@ const bulkRemoveCommentsOfValidator = [
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export {
|
|
||||||
bulkRemoveCommentsOfValidator
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
import { HttpStatusCode } from '@peertube/peertube-models'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { param, query } from 'express-validator'
|
import { param, query } from 'express-validator'
|
||||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
|
||||||
import { isValidRSSFeed } from '../../helpers/custom-validators/feeds.js'
|
import { isValidRSSFeed } from '../../helpers/custom-validators/feeds.js'
|
||||||
import { exists, isIdOrUUIDValid, isIdValid, toCompleteUUID } from '../../helpers/custom-validators/misc.js'
|
import { exists, isIdOrUUIDValid, isIdValid, toCompleteUUID } from '../../helpers/custom-validators/misc.js'
|
||||||
import {
|
import {
|
||||||
areValidationErrors,
|
areValidationErrors,
|
||||||
checkCanSeeVideo,
|
checkCanSeeVideo,
|
||||||
|
doesAccountHandleExist,
|
||||||
doesAccountIdExist,
|
doesAccountIdExist,
|
||||||
doesAccountNameWithHostExist,
|
doesChannelHandleExist,
|
||||||
|
doesChannelIdExist,
|
||||||
doesUserFeedTokenCorrespond,
|
doesUserFeedTokenCorrespond,
|
||||||
doesVideoChannelIdExist,
|
|
||||||
doesVideoChannelNameWithHostExist,
|
|
||||||
doesVideoExist
|
doesVideoExist
|
||||||
} from './shared/index.js'
|
} from './shared/index.js'
|
||||||
|
|
||||||
|
@ -90,10 +90,14 @@ const feedsAccountOrChannelFiltersValidator = [
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
if (req.query.accountId && !await doesAccountIdExist(req.query.accountId, res)) return
|
const { accountId, videoChannelId, accountName, videoChannelName } = req.query
|
||||||
if (req.query.videoChannelId && !await doesVideoChannelIdExist(req.query.videoChannelId, res)) return
|
const commonOptions = { res, checkManage: false, checkIsLocal: false }
|
||||||
if (req.query.accountName && !await doesAccountNameWithHostExist(req.query.accountName, res)) return
|
|
||||||
if (req.query.videoChannelName && !await doesVideoChannelNameWithHostExist(req.query.videoChannelName, res)) return
|
if (accountId && !await doesAccountIdExist({ id: accountId, ...commonOptions })) return
|
||||||
|
if (videoChannelId && !await doesChannelIdExist({ id: videoChannelId, ...commonOptions })) return
|
||||||
|
|
||||||
|
if (accountName && !await doesAccountHandleExist({ handle: accountName, ...commonOptions })) return
|
||||||
|
if (videoChannelName && !await doesChannelHandleExist({ handle: videoChannelName, ...commonOptions })) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
@ -107,7 +111,7 @@ const videoFeedsPodcastValidator = [
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await doesVideoChannelIdExist(req.query.videoChannelId, res)) return
|
if (!await doesChannelIdExist({ id: req.query.videoChannelId, checkManage: false, checkIsLocal: false, res })) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
@ -125,7 +129,7 @@ const videoSubscriptionFeedsValidator = [
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
if (!await doesAccountIdExist(req.query.accountId, res)) return
|
if (!await doesAccountIdExist({ id: req.query.accountId, res, checkIsLocal: true, checkManage: false })) return
|
||||||
if (!await doesUserFeedTokenCorrespond(res.locals.account.userId, req.query.token, res)) return
|
if (!await doesUserFeedTokenCorrespond(res.locals.account.userId, req.query.token, res)) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
|
@ -157,11 +161,11 @@ const videoCommentsFeedsValidator = [
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
feedsAccountOrChannelFiltersValidator,
|
||||||
feedsFormatValidator,
|
feedsFormatValidator,
|
||||||
setFeedFormatContentType,
|
setFeedFormatContentType,
|
||||||
setFeedPodcastContentType,
|
setFeedPodcastContentType,
|
||||||
feedsAccountOrChannelFiltersValidator,
|
videoCommentsFeedsValidator,
|
||||||
videoFeedsPodcastValidator,
|
videoFeedsPodcastValidator,
|
||||||
videoSubscriptionFeedsValidator,
|
videoSubscriptionFeedsValidator
|
||||||
videoCommentsFeedsValidator
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +1,73 @@
|
||||||
import { Response } from 'express'
|
|
||||||
import { AccountModel } from '@server/models/account/account.js'
|
|
||||||
import { UserModel } from '@server/models/user/user.js'
|
|
||||||
import { MAccountDefault } from '@server/types/models/index.js'
|
|
||||||
import { forceNumber } from '@peertube/peertube-core-utils'
|
import { forceNumber } from '@peertube/peertube-core-utils'
|
||||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
import { HttpStatusCode, UserRight } from '@peertube/peertube-models'
|
||||||
|
import { AccountModel } from '@server/models/account/account.js'
|
||||||
|
import { MAccountDefault } from '@server/types/models/index.js'
|
||||||
|
import { Response } from 'express'
|
||||||
|
import { checkUserCanManageAccount } from './users.js'
|
||||||
|
|
||||||
function doesAccountIdExist (id: number | string, res: Response, sendNotFound = true) {
|
export async function doesAccountIdExist (options: {
|
||||||
const promise = AccountModel.load(forceNumber(id))
|
id: string | number
|
||||||
|
res: Response
|
||||||
|
checkManage: boolean // Also check the user can manage the account
|
||||||
|
checkIsLocal: boolean // Also check this is a local channel
|
||||||
|
}) {
|
||||||
|
const { id, res, checkIsLocal, checkManage } = options
|
||||||
|
|
||||||
return doesAccountExist(promise, res, sendNotFound)
|
const account = await AccountModel.load(forceNumber(id))
|
||||||
|
|
||||||
|
return doesAccountExist({ account, res, checkIsLocal, checkManage })
|
||||||
}
|
}
|
||||||
|
|
||||||
function doesLocalAccountNameExist (name: string, res: Response, sendNotFound = true) {
|
export async function doesAccountHandleExist (options: {
|
||||||
const promise = AccountModel.loadLocalByName(name)
|
handle: string
|
||||||
|
res: Response
|
||||||
|
checkManage: boolean // Also check the user can manage the account
|
||||||
|
checkIsLocal: boolean // Also check this is a local channel
|
||||||
|
}) {
|
||||||
|
const { handle, res, checkIsLocal, checkManage } = options
|
||||||
|
|
||||||
return doesAccountExist(promise, res, sendNotFound)
|
const account = await AccountModel.loadByNameWithHost(handle)
|
||||||
|
|
||||||
|
return doesAccountExist({ account, res, checkIsLocal, checkManage })
|
||||||
}
|
}
|
||||||
|
|
||||||
function doesAccountNameWithHostExist (nameWithDomain: string, res: Response, sendNotFound = true) {
|
// ---------------------------------------------------------------------------
|
||||||
const promise = AccountModel.loadByNameWithHost(nameWithDomain)
|
// Private
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
return doesAccountExist(promise, res, sendNotFound)
|
function doesAccountExist (options: {
|
||||||
}
|
account: MAccountDefault
|
||||||
|
res: Response
|
||||||
async function doesAccountExist (p: Promise<MAccountDefault>, res: Response, sendNotFound: boolean) {
|
checkManage: boolean
|
||||||
const account = await p
|
checkIsLocal: boolean
|
||||||
|
}) {
|
||||||
|
const { account, res, checkIsLocal, checkManage } = options
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
if (sendNotFound === true) {
|
res.fail({
|
||||||
res.fail({
|
status: HttpStatusCode.NOT_FOUND_404,
|
||||||
status: HttpStatusCode.NOT_FOUND_404,
|
message: 'Account not found'
|
||||||
message: 'Account not found'
|
})
|
||||||
})
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkManage) {
|
||||||
|
const user = res.locals.oauth.token.User
|
||||||
|
|
||||||
|
if (!checkUserCanManageAccount({ account, user, res, specialRight: UserRight.MANAGE_USERS })) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkIsLocal && account.Actor.isOwned() === false) {
|
||||||
|
res.fail({
|
||||||
|
status: HttpStatusCode.FORBIDDEN_403,
|
||||||
|
message: 'This account is not owned.'
|
||||||
|
})
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
res.locals.account = account
|
res.locals.account = account
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doesUserFeedTokenCorrespond (id: number, token: string, res: Response) {
|
|
||||||
const user = await UserModel.loadByIdWithChannels(forceNumber(id))
|
|
||||||
|
|
||||||
if (token !== user.feedToken) {
|
|
||||||
res.fail({
|
|
||||||
status: HttpStatusCode.FORBIDDEN_403,
|
|
||||||
message: 'User and token mismatch'
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
res.locals.user = user
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
export {
|
|
||||||
doesAccountIdExist,
|
|
||||||
doesLocalAccountNameExist,
|
|
||||||
doesAccountNameWithHostExist,
|
|
||||||
doesAccountExist,
|
|
||||||
doesUserFeedTokenCorrespond
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,11 +12,15 @@ export function checkUserIdExist (idArg: number | string, res: express.Response,
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkUserEmailExistPermissive (email: string, res: express.Response, abortResponse = true) {
|
export function checkUserEmailExistPermissive (email: string, res: express.Response, abortResponse = true) {
|
||||||
return checkUserExist(async () => {
|
return checkUserExist(
|
||||||
const users = await UserModel.loadByEmailCaseInsensitive(email)
|
async () => {
|
||||||
|
const users = await UserModel.loadByEmailCaseInsensitive(email)
|
||||||
|
|
||||||
return getUserByEmailPermissive(users, email)
|
return getUserByEmailPermissive(users, email)
|
||||||
}, res, abortResponse)
|
},
|
||||||
|
res,
|
||||||
|
abortResponse
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkUsernameOrEmailDoNotAlreadyExist (username: string, email: string, res: express.Response) {
|
export async function checkUsernameOrEmailDoNotAlreadyExist (username: string, email: string, res: express.Response) {
|
||||||
|
@ -102,3 +106,18 @@ export function checkUserCanManageAccount (options: {
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function doesUserFeedTokenCorrespond (id: number, token: string, res: express.Response) {
|
||||||
|
const user = await UserModel.loadByIdWithChannels(forceNumber(id))
|
||||||
|
|
||||||
|
if (token !== user.feedToken) {
|
||||||
|
res.fail({
|
||||||
|
status: HttpStatusCode.FORBIDDEN_403,
|
||||||
|
message: 'User and token mismatch'
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
res.locals.user = user
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -1,29 +1,48 @@
|
||||||
import express from 'express'
|
import { HttpStatusCode, UserRight } from '@peertube/peertube-models'
|
||||||
import { VideoChannelModel } from '@server/models/video/video-channel.js'
|
import { VideoChannelModel } from '@server/models/video/video-channel.js'
|
||||||
import { MChannelBannerAccountDefault } from '@server/types/models/index.js'
|
import { MChannelBannerAccountDefault } from '@server/types/models/index.js'
|
||||||
import { HttpStatusCode } from '@peertube/peertube-models'
|
import express from 'express'
|
||||||
|
import { checkUserCanManageAccount } from './users.js'
|
||||||
|
|
||||||
async function doesVideoChannelIdExist (id: number, res: express.Response) {
|
export async function doesChannelIdExist (options: {
|
||||||
const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id)
|
id: number
|
||||||
|
checkManage: boolean // Also check the user can manage the account
|
||||||
|
checkIsLocal: boolean // Also check this is a local channel
|
||||||
|
res: express.Response
|
||||||
|
}) {
|
||||||
|
const { id, checkManage, checkIsLocal, res } = options
|
||||||
|
|
||||||
return processVideoChannelExist(videoChannel, res)
|
const channel = await VideoChannelModel.loadAndPopulateAccount(+id)
|
||||||
|
|
||||||
|
return processVideoChannelExist({ channel, checkManage, checkIsLocal, res })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: express.Response) {
|
export async function doesChannelHandleExist (options: {
|
||||||
const videoChannel = await VideoChannelModel.loadByNameWithHostAndPopulateAccount(nameWithDomain)
|
handle: string
|
||||||
|
checkManage: boolean // Also check the user can manage the account
|
||||||
|
checkIsLocal: boolean // Also check this is a local channel
|
||||||
|
res: express.Response
|
||||||
|
}) {
|
||||||
|
const { handle, checkManage, checkIsLocal, res } = options
|
||||||
|
|
||||||
return processVideoChannelExist(videoChannel, res)
|
const channel = await VideoChannelModel.loadByHandleAndPopulateAccount(handle)
|
||||||
|
|
||||||
|
return processVideoChannelExist({ channel, checkManage, checkIsLocal, res })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Private
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
function processVideoChannelExist (options: {
|
||||||
doesVideoChannelIdExist,
|
channel: MChannelBannerAccountDefault
|
||||||
doesVideoChannelNameWithHostExist
|
res: express.Response
|
||||||
}
|
checkManage: boolean
|
||||||
|
checkIsLocal: boolean
|
||||||
|
}) {
|
||||||
|
const { channel, res, checkManage, checkIsLocal } = options
|
||||||
|
|
||||||
function processVideoChannelExist (videoChannel: MChannelBannerAccountDefault, res: express.Response) {
|
if (!channel) {
|
||||||
if (!videoChannel) {
|
|
||||||
res.fail({
|
res.fail({
|
||||||
status: HttpStatusCode.NOT_FOUND_404,
|
status: HttpStatusCode.NOT_FOUND_404,
|
||||||
message: 'Video channel not found'
|
message: 'Video channel not found'
|
||||||
|
@ -31,6 +50,23 @@ function processVideoChannelExist (videoChannel: MChannelBannerAccountDefault, r
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
res.locals.videoChannel = videoChannel
|
if (checkManage) {
|
||||||
|
const user = res.locals.oauth.token.User
|
||||||
|
|
||||||
|
if (!checkUserCanManageAccount({ account: channel.Account, user, res, specialRight: UserRight.MANAGE_ANY_VIDEO_CHANNEL })) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkIsLocal && channel.Actor.isOwned() === false) {
|
||||||
|
res.fail({
|
||||||
|
status: HttpStatusCode.FORBIDDEN_403,
|
||||||
|
message: 'This channel is not owned.'
|
||||||
|
})
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
res.locals.videoChannel = channel
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { arrayify, forceNumber } from '@peertube/peertube-core-utils'
|
import { arrayify, forceNumber } from '@peertube/peertube-core-utils'
|
||||||
import { HttpStatusCode, ServerErrorCode, UserRight, UserRole } from '@peertube/peertube-models'
|
import { HttpStatusCode, ServerErrorCode, UserRole } from '@peertube/peertube-models'
|
||||||
import { isStringArray } from '@server/helpers/custom-validators/search.js'
|
import { isStringArray } from '@server/helpers/custom-validators/search.js'
|
||||||
import { Hooks } from '@server/lib/plugins/hooks.js'
|
import { Hooks } from '@server/lib/plugins/hooks.js'
|
||||||
|
import { MUser } from '@server/types/models/user/user.js'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { body, param, query } from 'express-validator'
|
import { body, param, query } from 'express-validator'
|
||||||
import { exists, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc.js'
|
import { exists, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc.js'
|
||||||
|
@ -34,11 +35,10 @@ import { ActorModel } from '../../../models/actor/actor.js'
|
||||||
import {
|
import {
|
||||||
areValidationErrors,
|
areValidationErrors,
|
||||||
checkEmailDoesNotAlreadyExist,
|
checkEmailDoesNotAlreadyExist,
|
||||||
checkUserCanManageAccount,
|
|
||||||
checkUserEmailExistPermissive,
|
checkUserEmailExistPermissive,
|
||||||
checkUserIdExist,
|
checkUserIdExist,
|
||||||
checkUsernameOrEmailDoNotAlreadyExist,
|
checkUsernameOrEmailDoNotAlreadyExist,
|
||||||
doesVideoChannelIdExist,
|
doesChannelIdExist,
|
||||||
doesVideoExist,
|
doesVideoExist,
|
||||||
isValidVideoIdParam
|
isValidVideoIdParam
|
||||||
} from '../shared/index.js'
|
} from '../shared/index.js'
|
||||||
|
@ -128,11 +128,13 @@ export const usersRemoveValidator = [
|
||||||
return res.fail({ message: 'Cannot remove the root user' })
|
return res.fail({ message: 'Cannot remove the root user' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!checkUserCanModerate(user, res)) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
export const usersBlockingValidator = [
|
export const usersBlockToggleValidator = [
|
||||||
param('id')
|
param('id')
|
||||||
.custom(isIdValid),
|
.custom(isIdValid),
|
||||||
body('reason')
|
body('reason')
|
||||||
|
@ -148,6 +150,8 @@ export const usersBlockingValidator = [
|
||||||
return res.fail({ message: 'Cannot block the root user' })
|
return res.fail({ message: 'Cannot block the root user' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!checkUserCanModerate(user, res)) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -201,6 +205,8 @@ export const usersUpdateValidator = [
|
||||||
return res.fail({ message: 'Cannot change root role.' })
|
return res.fail({ message: 'Cannot change root role.' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!checkUserCanModerate(user, res)) return
|
||||||
|
|
||||||
if (req.body.email && req.body.email !== user.email && !await checkEmailDoesNotAlreadyExist(req.body.email, res)) return
|
if (req.body.email && req.body.email !== user.email && !await checkEmailDoesNotAlreadyExist(req.body.email, res)) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
|
@ -328,7 +334,7 @@ export const usersVideosValidator = [
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
if (req.query.channelId && !await doesVideoChannelIdExist(req.query.channelId, res)) return
|
if (req.query.channelId && !await doesChannelIdExist({ id: req.query.channelId, checkManage: true, checkIsLocal: true, res })) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
@ -431,38 +437,20 @@ export const userAutocompleteValidator = [
|
||||||
.not().isEmpty()
|
.not().isEmpty()
|
||||||
]
|
]
|
||||||
|
|
||||||
export const ensureAuthUserOwnsAccountValidator = [
|
// ---------------------------------------------------------------------------
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
// Private
|
||||||
const user = res.locals.oauth.token.User
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
if (!checkUserCanManageAccount({ user, account: res.locals.account, specialRight: null, res })) return
|
function checkUserCanModerate (onUser: MUser, res: express.Response) {
|
||||||
|
const authUser = res.locals.oauth.token.User
|
||||||
|
|
||||||
return next()
|
if (authUser.role === UserRole.ADMINISTRATOR) return true
|
||||||
}
|
if (authUser.role === UserRole.MODERATOR && onUser.role === UserRole.USER) return true
|
||||||
]
|
|
||||||
|
|
||||||
export const ensureCanManageChannelOrAccount = [
|
res.fail({
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
status: HttpStatusCode.FORBIDDEN_403,
|
||||||
const user = res.locals.oauth.token.user
|
message: 'Users can only be managed by moderators or admins.'
|
||||||
const account = res.locals.videoChannel?.Account ?? res.locals.account
|
})
|
||||||
|
|
||||||
if (!checkUserCanManageAccount({ account, user, res, specialRight: UserRight.MANAGE_ANY_VIDEO_CHANNEL })) return
|
return false
|
||||||
|
}
|
||||||
return next()
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
export const ensureCanModerateUser = [
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
||||||
const authUser = res.locals.oauth.token.User
|
|
||||||
const onUser = res.locals.user
|
|
||||||
|
|
||||||
if (authUser.role === UserRole.ADMINISTRATOR) return next()
|
|
||||||
if (authUser.role === UserRole.MODERATOR && onUser.role === UserRole.USER) return next()
|
|
||||||
|
|
||||||
return res.fail({
|
|
||||||
status: HttpStatusCode.FORBIDDEN_403,
|
|
||||||
message: 'Users can only be managed by moderators or admins.'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.j
|
||||||
import { CONFIG } from '@server/initializers/config.js'
|
import { CONFIG } from '@server/initializers/config.js'
|
||||||
import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync.js'
|
import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync.js'
|
||||||
import { HttpStatusCode, VideoChannelSyncCreate } from '@peertube/peertube-models'
|
import { HttpStatusCode, VideoChannelSyncCreate } from '@peertube/peertube-models'
|
||||||
import { areValidationErrors, doesVideoChannelIdExist } from '../shared/index.js'
|
import { areValidationErrors, doesChannelIdExist } from '../shared/index.js'
|
||||||
import { doesVideoChannelSyncIdExist } from '../shared/video-channel-syncs.js'
|
import { doesVideoChannelSyncIdExist } from '../shared/video-channel-syncs.js'
|
||||||
|
|
||||||
export const ensureSyncIsEnabled = (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
export const ensureSyncIsEnabled = (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
|
@ -29,7 +29,7 @@ export const videoChannelSyncValidator = [
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
const body: VideoChannelSyncCreate = req.body
|
const body: VideoChannelSyncCreate = req.body
|
||||||
if (!await doesVideoChannelIdExist(body.videoChannelId, res)) return
|
if (!await doesChannelIdExist({ id: body.videoChannelId, checkManage: true, checkIsLocal: true, res })) return
|
||||||
|
|
||||||
const count = await VideoChannelSyncModel.countByAccount(res.locals.videoChannel.accountId)
|
const count = await VideoChannelSyncModel.countByAccount(res.locals.videoChannel.accountId)
|
||||||
if (count >= CONFIG.IMPORT.VIDEO_CHANNEL_SYNCHRONIZATION.MAX_PER_USER) {
|
if (count >= CONFIG.IMPORT.VIDEO_CHANNEL_SYNCHRONIZATION.MAX_PER_USER) {
|
||||||
|
@ -49,7 +49,7 @@ export const ensureSyncExists = [
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
if (!await doesVideoChannelSyncIdExist(+req.params.id, res)) return
|
if (!await doesVideoChannelSyncIdExist(+req.params.id, res)) return
|
||||||
if (!await doesVideoChannelIdExist(res.locals.videoChannelSync.videoChannelId, res)) return
|
if (!await doesChannelIdExist({ id: res.locals.videoChannelSync.videoChannelId, checkManage: true, checkIsLocal: true, res })) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import express from 'express'
|
|
||||||
import { body, param, query } from 'express-validator'
|
|
||||||
import { HttpStatusCode, VideosImportInChannelCreate } from '@peertube/peertube-models'
|
import { HttpStatusCode, VideosImportInChannelCreate } from '@peertube/peertube-models'
|
||||||
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc.js'
|
||||||
import { CONFIG } from '@server/initializers/config.js'
|
import { CONFIG } from '@server/initializers/config.js'
|
||||||
import { MChannelAccountDefault } from '@server/types/models/index.js'
|
import { MChannelAccountDefault } from '@server/types/models/index.js'
|
||||||
|
import express from 'express'
|
||||||
|
import { body, param, query } from 'express-validator'
|
||||||
import { isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc.js'
|
import { isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc.js'
|
||||||
import {
|
import {
|
||||||
isVideoChannelDescriptionValid,
|
isVideoChannelDescriptionValid,
|
||||||
|
@ -13,7 +13,7 @@ import {
|
||||||
} from '../../../helpers/custom-validators/video-channels.js'
|
} from '../../../helpers/custom-validators/video-channels.js'
|
||||||
import { ActorModel } from '../../../models/actor/actor.js'
|
import { ActorModel } from '../../../models/actor/actor.js'
|
||||||
import { VideoChannelModel } from '../../../models/video/video-channel.js'
|
import { VideoChannelModel } from '../../../models/video/video-channel.js'
|
||||||
import { areValidationErrors, checkUserQuota, doesVideoChannelNameWithHostExist } from '../shared/index.js'
|
import { areValidationErrors, checkUserQuota, doesChannelHandleExist } from '../shared/index.js'
|
||||||
import { doesVideoChannelSyncIdExist } from '../shared/video-channel-syncs.js'
|
import { doesVideoChannelSyncIdExist } from '../shared/video-channel-syncs.js'
|
||||||
|
|
||||||
export const videoChannelsAddValidator = [
|
export const videoChannelsAddValidator = [
|
||||||
|
@ -82,31 +82,25 @@ export const videoChannelsRemoveValidator = [
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
export const videoChannelsNameWithHostValidator = [
|
export const videoChannelsHandleValidatorFactory = (options: {
|
||||||
param('nameWithHost')
|
checkIsLocal: boolean
|
||||||
.exists(),
|
checkManage: boolean
|
||||||
|
}) => {
|
||||||
|
const { checkIsLocal, checkManage } = options
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
return [
|
||||||
if (areValidationErrors(req, res)) return
|
param('nameWithHost')
|
||||||
|
.exists(),
|
||||||
|
|
||||||
if (!await doesVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
return next()
|
if (!await doesChannelHandleExist({ handle: req.params.nameWithHost, checkManage, checkIsLocal, res })) return
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
export const ensureIsLocalChannel = [
|
return next()
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
|
||||||
if (res.locals.videoChannel.Actor.isOwned() === false) {
|
|
||||||
return res.fail({
|
|
||||||
status: HttpStatusCode.FORBIDDEN_403,
|
|
||||||
message: 'This channel is not owned.'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
]
|
||||||
return next()
|
}
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
export const ensureChannelOwnerCanUpload = [
|
export const ensureChannelOwnerCanUpload = [
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
|
|
|
@ -24,7 +24,7 @@ import {
|
||||||
checkCanSeeVideo,
|
checkCanSeeVideo,
|
||||||
checkUserCanManageAccount,
|
checkUserCanManageAccount,
|
||||||
checkUserCanManageVideo,
|
checkUserCanManageVideo,
|
||||||
doesVideoChannelIdExist,
|
doesChannelIdExist,
|
||||||
doesVideoCommentExist,
|
doesVideoCommentExist,
|
||||||
doesVideoCommentThreadExist,
|
doesVideoCommentThreadExist,
|
||||||
doesVideoExist,
|
doesVideoExist,
|
||||||
|
@ -51,7 +51,9 @@ export const listAllVideoCommentsForAdminValidator = [
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
if (req.query.videoId && !await doesVideoExist(req.query.videoId, res, 'unsafe-only-immutable-attributes')) return
|
if (req.query.videoId && !await doesVideoExist(req.query.videoId, res, 'unsafe-only-immutable-attributes')) return
|
||||||
if (req.query.videoChannelId && !await doesVideoChannelIdExist(req.query.videoChannelId, res)) return
|
if (
|
||||||
|
req.query.videoChannelId && !await doesChannelIdExist({ id: req.query.videoChannelId, checkManage: true, checkIsLocal: true, res })
|
||||||
|
) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
@ -70,7 +72,9 @@ export const listCommentsOnUserVideosValidator = [
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
|
|
||||||
if (req.query.videoId && !await doesVideoExist(req.query.videoId, res, 'all')) return
|
if (req.query.videoId && !await doesVideoExist(req.query.videoId, res, 'all')) return
|
||||||
if (req.query.videoChannelId && !await doesVideoChannelIdExist(req.query.videoChannelId, res)) return
|
if (
|
||||||
|
req.query.videoChannelId && !await doesChannelIdExist({ id: req.query.videoChannelId, checkManage: true, checkIsLocal: true, res })
|
||||||
|
) return
|
||||||
|
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ import { WatchedWordsListModel } from '@server/models/watched-words/watched-word
|
||||||
import { MAccountId, MWatchedWordsList } from '@server/types/models/index.js'
|
import { MAccountId, MWatchedWordsList } from '@server/types/models/index.js'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { ValidationChain, body, param } from 'express-validator'
|
import { ValidationChain, body, param } from 'express-validator'
|
||||||
import { doesAccountNameWithHostExist } from './shared/accounts.js'
|
import { doesAccountHandleExist } from './shared/accounts.js'
|
||||||
import { checkUserCanManageAccount } from './shared/users.js'
|
|
||||||
import { areValidationErrors } from './shared/utils.js'
|
import { areValidationErrors } from './shared/utils.js'
|
||||||
|
|
||||||
export const manageAccountWatchedWordsListValidator = [
|
export const manageAccountWatchedWordsListValidator = [
|
||||||
|
@ -17,8 +16,7 @@ export const manageAccountWatchedWordsListValidator = [
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await doesAccountNameWithHostExist(req.params.accountName, res)) return
|
if (!await doesAccountHandleExist({ handle: req.params.accountName, res, checkIsLocal: true, checkManage: true })) return
|
||||||
if (!checkUserCanManageAccount({ user: res.locals.oauth.token.User, account: res.locals.account, specialRight: null, res })) return
|
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
|
@ -59,14 +57,14 @@ function buildUpdateOrAddValidators ({ optional }: { optional: boolean }) {
|
||||||
.trim()
|
.trim()
|
||||||
.custom(isWatchedWordListNameValid).withMessage(
|
.custom(isWatchedWordListNameValid).withMessage(
|
||||||
`Should have a list name between ` +
|
`Should have a list name between ` +
|
||||||
`${CONSTRAINTS_FIELDS.WATCHED_WORDS.LIST_NAME.min} and ${CONSTRAINTS_FIELDS.WATCHED_WORDS.LIST_NAME.max} characters long`
|
`${CONSTRAINTS_FIELDS.WATCHED_WORDS.LIST_NAME.min} and ${CONSTRAINTS_FIELDS.WATCHED_WORDS.LIST_NAME.max} characters long`
|
||||||
),
|
),
|
||||||
|
|
||||||
makeOptionalIfNeeded(body('words'))
|
makeOptionalIfNeeded(body('words'))
|
||||||
.custom(areWatchedWordsValid)
|
.custom(areWatchedWordsValid)
|
||||||
.withMessage(
|
.withMessage(
|
||||||
`Should have an array of up to ${CONSTRAINTS_FIELDS.WATCHED_WORDS.WORDS.max} words between ` +
|
`Should have an array of up to ${CONSTRAINTS_FIELDS.WATCHED_WORDS.WORDS.max} words between ` +
|
||||||
`${CONSTRAINTS_FIELDS.WATCHED_WORDS.WORD.min} and ${CONSTRAINTS_FIELDS.WATCHED_WORDS.WORD.max} characters each`
|
`${CONSTRAINTS_FIELDS.WATCHED_WORDS.WORD.min} and ${CONSTRAINTS_FIELDS.WATCHED_WORDS.WORD.max} characters each`
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -725,8 +725,8 @@ export class VideoChannelModel extends SequelizeModel<VideoChannelModel> {
|
||||||
.findOne(query)
|
.findOne(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
static loadByNameWithHostAndPopulateAccount (nameWithHost: string) {
|
static loadByHandleAndPopulateAccount (handle: string) {
|
||||||
const [ name, host ] = nameWithHost.split('@')
|
const [ name, host ] = handle.split('@')
|
||||||
|
|
||||||
if (!host || host === WEBSERVER.HOST) return VideoChannelModel.loadLocalByNameAndPopulateAccount(name)
|
if (!host || host === WEBSERVER.HOST) return VideoChannelModel.loadLocalByNameAndPopulateAccount(name)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue