aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers')
-rw-r--r--server/controllers/activitypub/client.ts49
-rw-r--r--server/controllers/activitypub/inbox.ts6
-rw-r--r--server/controllers/api/accounts.ts13
-rw-r--r--server/controllers/api/config.ts33
-rw-r--r--server/controllers/api/index.ts4
-rw-r--r--server/controllers/api/jobs.ts2
-rw-r--r--server/controllers/api/overviews.ts2
-rw-r--r--server/controllers/api/server/debug.ts6
-rw-r--r--server/controllers/api/server/follows.ts5
-rw-r--r--server/controllers/api/server/logs.ts10
-rw-r--r--server/controllers/api/server/redundancy.ts84
-rw-r--r--server/controllers/api/server/stats.ts10
-rw-r--r--server/controllers/api/users/index.ts18
-rw-r--r--server/controllers/api/users/me.ts4
-rw-r--r--server/controllers/api/users/my-subscriptions.ts6
-rw-r--r--server/controllers/api/video-channel.ts3
-rw-r--r--server/controllers/api/video-playlist.ts1
-rw-r--r--server/controllers/api/videos/captions.ts2
-rw-r--r--server/controllers/api/videos/import.ts22
-rw-r--r--server/controllers/api/videos/index.ts7
-rw-r--r--server/controllers/client.ts2
-rw-r--r--server/controllers/static.ts33
-rw-r--r--server/controllers/tracker.ts15
-rw-r--r--server/controllers/webfinger.ts4
24 files changed, 218 insertions, 123 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index 62412cd62..84828e7e0 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -1,4 +1,3 @@
1// Intercept ActivityPub client requests
2import * as express from 'express' 1import * as express from 'express'
3import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' 2import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos'
4import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' 3import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub'
@@ -14,7 +13,7 @@ import {
14 videosCustomGetValidator, 13 videosCustomGetValidator,
15 videosShareValidator 14 videosShareValidator
16} from '../../middlewares' 15} from '../../middlewares'
17import { getAccountVideoRateValidator, videoCommentGetValidator } from '../../middlewares/validators' 16import { getAccountVideoRateValidatorFactory, videoCommentGetValidator } from '../../middlewares/validators'
18import { AccountModel } from '../../models/account/account' 17import { AccountModel } from '../../models/account/account'
19import { ActorFollowModel } from '../../models/activitypub/actor-follow' 18import { ActorFollowModel } from '../../models/activitypub/actor-follow'
20import { VideoModel } from '../../models/video/video' 19import { VideoModel } from '../../models/video/video'
@@ -37,10 +36,12 @@ import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike'
37import { videoPlaylistElementAPGetValidator, videoPlaylistsGetValidator } from '../../middlewares/validators/videos/video-playlists' 36import { videoPlaylistElementAPGetValidator, videoPlaylistsGetValidator } from '../../middlewares/validators/videos/video-playlists'
38import { VideoPlaylistModel } from '../../models/video/video-playlist' 37import { VideoPlaylistModel } from '../../models/video/video-playlist'
39import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' 38import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
40import { MAccountId, MActorId, MVideo, MVideoAPWithoutCaption } from '@server/typings/models' 39import { MAccountId, MActorId, MVideoAPWithoutCaption, MVideoId } from '@server/typings/models'
41 40
42const activityPubClientRouter = express.Router() 41const activityPubClientRouter = express.Router()
43 42
43// Intercept ActivityPub client requests
44
44activityPubClientRouter.get('/accounts?/:name', 45activityPubClientRouter.get('/accounts?/:name',
45 executeIfActivityPub, 46 executeIfActivityPub,
46 asyncMiddleware(localAccountValidator), 47 asyncMiddleware(localAccountValidator),
@@ -63,13 +64,13 @@ activityPubClientRouter.get('/accounts?/:name/playlists',
63) 64)
64activityPubClientRouter.get('/accounts?/:name/likes/:videoId', 65activityPubClientRouter.get('/accounts?/:name/likes/:videoId',
65 executeIfActivityPub, 66 executeIfActivityPub,
66 asyncMiddleware(getAccountVideoRateValidator('like')), 67 asyncMiddleware(getAccountVideoRateValidatorFactory('like')),
67 getAccountVideoRate('like') 68 getAccountVideoRateFactory('like')
68) 69)
69activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId', 70activityPubClientRouter.get('/accounts?/:name/dislikes/:videoId',
70 executeIfActivityPub, 71 executeIfActivityPub,
71 asyncMiddleware(getAccountVideoRateValidator('dislike')), 72 asyncMiddleware(getAccountVideoRateValidatorFactory('dislike')),
72 getAccountVideoRate('dislike') 73 getAccountVideoRateFactory('dislike')
73) 74)
74 75
75activityPubClientRouter.get('/videos/watch/:id', 76activityPubClientRouter.get('/videos/watch/:id',
@@ -85,7 +86,7 @@ activityPubClientRouter.get('/videos/watch/:id/activity',
85) 86)
86activityPubClientRouter.get('/videos/watch/:id/announces', 87activityPubClientRouter.get('/videos/watch/:id/announces',
87 executeIfActivityPub, 88 executeIfActivityPub,
88 asyncMiddleware(videosCustomGetValidator('only-video')), 89 asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
89 asyncMiddleware(videoAnnouncesController) 90 asyncMiddleware(videoAnnouncesController)
90) 91)
91activityPubClientRouter.get('/videos/watch/:id/announces/:actorId', 92activityPubClientRouter.get('/videos/watch/:id/announces/:actorId',
@@ -95,17 +96,17 @@ activityPubClientRouter.get('/videos/watch/:id/announces/:actorId',
95) 96)
96activityPubClientRouter.get('/videos/watch/:id/likes', 97activityPubClientRouter.get('/videos/watch/:id/likes',
97 executeIfActivityPub, 98 executeIfActivityPub,
98 asyncMiddleware(videosCustomGetValidator('only-video')), 99 asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
99 asyncMiddleware(videoLikesController) 100 asyncMiddleware(videoLikesController)
100) 101)
101activityPubClientRouter.get('/videos/watch/:id/dislikes', 102activityPubClientRouter.get('/videos/watch/:id/dislikes',
102 executeIfActivityPub, 103 executeIfActivityPub,
103 asyncMiddleware(videosCustomGetValidator('only-video')), 104 asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
104 asyncMiddleware(videoDislikesController) 105 asyncMiddleware(videoDislikesController)
105) 106)
106activityPubClientRouter.get('/videos/watch/:id/comments', 107activityPubClientRouter.get('/videos/watch/:id/comments',
107 executeIfActivityPub, 108 executeIfActivityPub,
108 asyncMiddleware(videosCustomGetValidator('only-video')), 109 asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
109 asyncMiddleware(videoCommentsController) 110 asyncMiddleware(videoCommentsController)
110) 111)
111activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId', 112activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',
@@ -122,7 +123,7 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity
122activityPubClientRouter.get('/video-channels/:name', 123activityPubClientRouter.get('/video-channels/:name',
123 executeIfActivityPub, 124 executeIfActivityPub,
124 asyncMiddleware(localVideoChannelValidator), 125 asyncMiddleware(localVideoChannelValidator),
125 asyncMiddleware(videoChannelController) 126 videoChannelController
126) 127)
127activityPubClientRouter.get('/video-channels/:name/followers', 128activityPubClientRouter.get('/video-channels/:name/followers',
128 executeIfActivityPub, 129 executeIfActivityPub,
@@ -154,7 +155,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId',
154activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', 155activityPubClientRouter.get('/video-playlists/:playlistId/:videoId',
155 executeIfActivityPub, 156 executeIfActivityPub,
156 asyncMiddleware(videoPlaylistElementAPGetValidator), 157 asyncMiddleware(videoPlaylistElementAPGetValidator),
157 asyncMiddleware(videoPlaylistElementController) 158 videoPlaylistElementController
158) 159)
159 160
160// --------------------------------------------------------------------------- 161// ---------------------------------------------------------------------------
@@ -192,7 +193,7 @@ async function accountPlaylistsController (req: express.Request, res: express.Re
192 return activityPubResponse(activityPubContextify(activityPubResult), res) 193 return activityPubResponse(activityPubContextify(activityPubResult), res)
193} 194}
194 195
195function getAccountVideoRate (rateType: VideoRateType) { 196function getAccountVideoRateFactory (rateType: VideoRateType) {
196 return (req: express.Request, res: express.Response) => { 197 return (req: express.Request, res: express.Response) => {
197 const accountVideoRate = res.locals.accountVideoRate 198 const accountVideoRate = res.locals.accountVideoRate
198 199
@@ -234,11 +235,11 @@ async function videoAnnounceController (req: express.Request, res: express.Respo
234 235
235 const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined) 236 const { activity } = await buildAnnounceWithVideoAudience(share.Actor, share, res.locals.videoAll, undefined)
236 237
237 return activityPubResponse(activityPubContextify(activity), res) 238 return activityPubResponse(activityPubContextify(activity, 'Announce'), res)
238} 239}
239 240
240async function videoAnnouncesController (req: express.Request, res: express.Response) { 241async function videoAnnouncesController (req: express.Request, res: express.Response) {
241 const video = res.locals.onlyVideo 242 const video = res.locals.onlyImmutableVideo
242 243
243 const handler = async (start: number, count: number) => { 244 const handler = async (start: number, count: number) => {
244 const result = await VideoShareModel.listAndCountByVideoId(video.id, start, count) 245 const result = await VideoShareModel.listAndCountByVideoId(video.id, start, count)
@@ -253,21 +254,21 @@ async function videoAnnouncesController (req: express.Request, res: express.Resp
253} 254}
254 255
255async function videoLikesController (req: express.Request, res: express.Response) { 256async function videoLikesController (req: express.Request, res: express.Response) {
256 const video = res.locals.onlyVideo 257 const video = res.locals.onlyImmutableVideo
257 const json = await videoRates(req, 'like', video, getVideoLikesActivityPubUrl(video)) 258 const json = await videoRates(req, 'like', video, getVideoLikesActivityPubUrl(video))
258 259
259 return activityPubResponse(activityPubContextify(json), res) 260 return activityPubResponse(activityPubContextify(json), res)
260} 261}
261 262
262async function videoDislikesController (req: express.Request, res: express.Response) { 263async function videoDislikesController (req: express.Request, res: express.Response) {
263 const video = res.locals.onlyVideo 264 const video = res.locals.onlyImmutableVideo
264 const json = await videoRates(req, 'dislike', video, getVideoDislikesActivityPubUrl(video)) 265 const json = await videoRates(req, 'dislike', video, getVideoDislikesActivityPubUrl(video))
265 266
266 return activityPubResponse(activityPubContextify(json), res) 267 return activityPubResponse(activityPubContextify(json), res)
267} 268}
268 269
269async function videoCommentsController (req: express.Request, res: express.Response) { 270async function videoCommentsController (req: express.Request, res: express.Response) {
270 const video = res.locals.onlyVideo 271 const video = res.locals.onlyImmutableVideo
271 272
272 const handler = async (start: number, count: number) => { 273 const handler = async (start: number, count: number) => {
273 const result = await VideoCommentModel.listAndCountByVideoId(video.id, start, count) 274 const result = await VideoCommentModel.listAndCountByVideoId(video.id, start, count)
@@ -281,7 +282,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo
281 return activityPubResponse(activityPubContextify(json), res) 282 return activityPubResponse(activityPubContextify(json), res)
282} 283}
283 284
284async function videoChannelController (req: express.Request, res: express.Response) { 285function videoChannelController (req: express.Request, res: express.Response) {
285 const videoChannel = res.locals.videoChannel 286 const videoChannel = res.locals.videoChannel
286 287
287 return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res) 288 return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
@@ -334,10 +335,10 @@ async function videoRedundancyController (req: express.Request, res: express.Res
334 335
335 if (req.path.endsWith('/activity')) { 336 if (req.path.endsWith('/activity')) {
336 const data = buildCreateActivity(videoRedundancy.url, serverActor, object, audience) 337 const data = buildCreateActivity(videoRedundancy.url, serverActor, object, audience)
337 return activityPubResponse(activityPubContextify(data), res) 338 return activityPubResponse(activityPubContextify(data, 'CacheFile'), res)
338 } 339 }
339 340
340 return activityPubResponse(activityPubContextify(object), res) 341 return activityPubResponse(activityPubContextify(object, 'CacheFile'), res)
341} 342}
342 343
343async function videoPlaylistController (req: express.Request, res: express.Response) { 344async function videoPlaylistController (req: express.Request, res: express.Response) {
@@ -353,7 +354,7 @@ async function videoPlaylistController (req: express.Request, res: express.Respo
353 return activityPubResponse(activityPubContextify(object), res) 354 return activityPubResponse(activityPubContextify(object), res)
354} 355}
355 356
356async function videoPlaylistElementController (req: express.Request, res: express.Response) { 357function videoPlaylistElementController (req: express.Request, res: express.Response) {
357 const videoPlaylistElement = res.locals.videoPlaylistElementAP 358 const videoPlaylistElement = res.locals.videoPlaylistElementAP
358 359
359 const json = videoPlaylistElement.toActivityPubObject() 360 const json = videoPlaylistElement.toActivityPubObject()
@@ -386,7 +387,7 @@ async function actorPlaylists (req: express.Request, account: MAccountId) {
386 return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page) 387 return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page)
387} 388}
388 389
389function videoRates (req: express.Request, rateType: VideoRateType, video: MVideo, url: string) { 390function videoRates (req: express.Request, rateType: VideoRateType, video: MVideoId, url: string) {
390 const handler = async (start: number, count: number) => { 391 const handler = async (start: number, count: number) => {
391 const result = await AccountVideoRateModel.listAndCountAccountUrlsByVideoId(rateType, video.id, start, count) 392 const result = await AccountVideoRateModel.listAndCountAccountUrlsByVideoId(rateType, video.id, start, count)
392 return { 393 return {
diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts
index ca42106b8..3b8fb34a8 100644
--- a/server/controllers/activitypub/inbox.ts
+++ b/server/controllers/activitypub/inbox.ts
@@ -46,11 +46,15 @@ const inboxQueue = queue<QueueParam, Error>((task, cb) => {
46 46
47 processActivities(task.activities, options) 47 processActivities(task.activities, options)
48 .then(() => cb()) 48 .then(() => cb())
49 .catch(err => {
50 logger.error('Error in process activities.', { err })
51 cb()
52 })
49}) 53})
50 54
51function inboxController (req: express.Request, res: express.Response) { 55function inboxController (req: express.Request, res: express.Response) {
52 const rootActivity: RootActivity = req.body 56 const rootActivity: RootActivity = req.body
53 let activities: Activity[] = [] 57 let activities: Activity[]
54 58
55 if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) { 59 if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) {
56 activities = (rootActivity as ActivityPubCollection).items 60 activities = (rootActivity as ActivityPubCollection).items
diff --git a/server/controllers/api/accounts.ts b/server/controllers/api/accounts.ts
index 05740318e..f354ccf24 100644
--- a/server/controllers/api/accounts.ts
+++ b/server/controllers/api/accounts.ts
@@ -16,21 +16,17 @@ import {
16 accountNameWithHostGetValidator, 16 accountNameWithHostGetValidator,
17 accountsSortValidator, 17 accountsSortValidator,
18 ensureAuthUserOwnsAccountValidator, 18 ensureAuthUserOwnsAccountValidator,
19 videosSortValidator, 19 videoChannelsSortValidator,
20 videoChannelsSortValidator 20 videosSortValidator
21} from '../../middlewares/validators' 21} from '../../middlewares/validators'
22import { AccountModel } from '../../models/account/account' 22import { AccountModel } from '../../models/account/account'
23import { AccountVideoRateModel } from '../../models/account/account-video-rate' 23import { AccountVideoRateModel } from '../../models/account/account-video-rate'
24import { VideoModel } from '../../models/video/video' 24import { VideoModel } from '../../models/video/video'
25import { buildNSFWFilter, isUserAbleToSearchRemoteURI, getCountVideos } from '../../helpers/express-utils' 25import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
26import { VideoChannelModel } from '../../models/video/video-channel' 26import { VideoChannelModel } from '../../models/video/video-channel'
27import { JobQueue } from '../../lib/job-queue' 27import { JobQueue } from '../../lib/job-queue'
28import { logger } from '../../helpers/logger'
29import { VideoPlaylistModel } from '../../models/video/video-playlist' 28import { VideoPlaylistModel } from '../../models/video/video-playlist'
30import { 29import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists'
31 commonVideoPlaylistFiltersValidator,
32 videoPlaylistsSearchValidator
33} from '../../middlewares/validators/videos/video-playlists'
34 30
35const accountsRouter = express.Router() 31const accountsRouter = express.Router()
36 32
@@ -104,7 +100,6 @@ function getAccount (req: express.Request, res: express.Response) {
104 100
105 if (account.isOutdated()) { 101 if (account.isOutdated()) {
106 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) 102 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } })
107 .catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err }))
108 } 103 }
109 104
110 return res.json(account.toFormattedJSON()) 105 return res.json(account.toFormattedJSON())
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts
index ae4e00248..06fe30371 100644
--- a/server/controllers/api/config.ts
+++ b/server/controllers/api/config.ts
@@ -11,10 +11,9 @@ import { ClientHtml } from '../../lib/client-html'
11import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger' 11import { auditLoggerFactory, CustomConfigAuditView, getAuditIdFromRes } from '../../helpers/audit-logger'
12import { remove, writeJSON } from 'fs-extra' 12import { remove, writeJSON } from 'fs-extra'
13import { getServerCommit } from '../../helpers/utils' 13import { getServerCommit } from '../../helpers/utils'
14import { Emailer } from '../../lib/emailer'
15import validator from 'validator' 14import validator from 'validator'
16import { objectConverter } from '../../helpers/core-utils' 15import { objectConverter } from '../../helpers/core-utils'
17import { CONFIG, reloadConfig } from '../../initializers/config' 16import { CONFIG, isEmailEnabled, reloadConfig } from '../../initializers/config'
18import { PluginManager } from '../../lib/plugins/plugin-manager' 17import { PluginManager } from '../../lib/plugins/plugin-manager'
19import { getThemeOrDefault } from '../../lib/plugins/theme-utils' 18import { getThemeOrDefault } from '../../lib/plugins/theme-utils'
20import { Hooks } from '@server/lib/plugins/hooks' 19import { Hooks } from '@server/lib/plugins/hooks'
@@ -31,12 +30,12 @@ configRouter.get('/',
31configRouter.get('/custom', 30configRouter.get('/custom',
32 authenticate, 31 authenticate,
33 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), 32 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
34 asyncMiddleware(getCustomConfig) 33 getCustomConfig
35) 34)
36configRouter.put('/custom', 35configRouter.put('/custom',
37 authenticate, 36 authenticate,
38 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), 37 ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
39 asyncMiddleware(customConfigUpdateValidator), 38 customConfigUpdateValidator,
40 asyncMiddleware(updateCustomConfig) 39 asyncMiddleware(updateCustomConfig)
41) 40)
42configRouter.delete('/custom', 41configRouter.delete('/custom',
@@ -73,6 +72,12 @@ async function getConfig (req: express.Request, res: express.Response) {
73 css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS 72 css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
74 } 73 }
75 }, 74 },
75 search: {
76 remoteUri: {
77 users: CONFIG.SEARCH.REMOTE_URI.USERS,
78 anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
79 }
80 },
76 plugin: { 81 plugin: {
77 registered: getRegisteredPlugins() 82 registered: getRegisteredPlugins()
78 }, 83 },
@@ -81,7 +86,7 @@ async function getConfig (req: express.Request, res: express.Response) {
81 default: defaultTheme 86 default: defaultTheme
82 }, 87 },
83 email: { 88 email: {
84 enabled: Emailer.isEnabled() 89 enabled: isEmailEnabled()
85 }, 90 },
86 contactForm: { 91 contactForm: {
87 enabled: CONFIG.CONTACT_FORM.ENABLED 92 enabled: CONFIG.CONTACT_FORM.ENABLED
@@ -196,7 +201,7 @@ function getAbout (req: express.Request, res: express.Response) {
196 return res.json(about).end() 201 return res.json(about).end()
197} 202}
198 203
199async function getCustomConfig (req: express.Request, res: express.Response) { 204function getCustomConfig (req: express.Request, res: express.Response) {
200 const data = customConfig() 205 const data = customConfig()
201 206
202 return res.json(data).end() 207 return res.json(data).end()
@@ -250,7 +255,7 @@ function getRegisteredThemes () {
250 255
251function getEnabledResolutions () { 256function getEnabledResolutions () {
252 return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) 257 return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
253 .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[ key ] === true) 258 .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
254 .map(r => parseInt(r, 10)) 259 .map(r => parseInt(r, 10))
255} 260}
256 261
@@ -340,13 +345,13 @@ function customConfig (): CustomConfig {
340 allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, 345 allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
341 threads: CONFIG.TRANSCODING.THREADS, 346 threads: CONFIG.TRANSCODING.THREADS,
342 resolutions: { 347 resolutions: {
343 '0p': CONFIG.TRANSCODING.RESOLUTIONS[ '0p' ], 348 '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'],
344 '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], 349 '240p': CONFIG.TRANSCODING.RESOLUTIONS['240p'],
345 '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], 350 '360p': CONFIG.TRANSCODING.RESOLUTIONS['360p'],
346 '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], 351 '480p': CONFIG.TRANSCODING.RESOLUTIONS['480p'],
347 '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], 352 '720p': CONFIG.TRANSCODING.RESOLUTIONS['720p'],
348 '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ], 353 '1080p': CONFIG.TRANSCODING.RESOLUTIONS['1080p'],
349 '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ] 354 '2160p': CONFIG.TRANSCODING.RESOLUTIONS['2160p']
350 }, 355 },
351 webtorrent: { 356 webtorrent: {
352 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED 357 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts
index 6138a32de..7bec6c527 100644
--- a/server/controllers/api/index.ts
+++ b/server/controllers/api/index.ts
@@ -1,5 +1,4 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as RateLimit from 'express-rate-limit'
3import { configRouter } from './config' 2import { configRouter } from './config'
4import { jobsRouter } from './jobs' 3import { jobsRouter } from './jobs'
5import { oauthClientsRouter } from './oauth-clients' 4import { oauthClientsRouter } from './oauth-clients'
@@ -15,6 +14,7 @@ import { overviewsRouter } from './overviews'
15import { videoPlaylistRouter } from './video-playlist' 14import { videoPlaylistRouter } from './video-playlist'
16import { CONFIG } from '../../initializers/config' 15import { CONFIG } from '../../initializers/config'
17import { pluginRouter } from './plugins' 16import { pluginRouter } from './plugins'
17import * as RateLimit from 'express-rate-limit'
18 18
19const apiRouter = express.Router() 19const apiRouter = express.Router()
20 20
@@ -24,8 +24,6 @@ apiRouter.use(cors({
24 credentials: true 24 credentials: true
25})) 25}))
26 26
27// FIXME: https://github.com/nfriedly/express-rate-limit/issues/138
28// @ts-ignore
29const apiRateLimiter = RateLimit({ 27const apiRateLimiter = RateLimit({
30 windowMs: CONFIG.RATES_LIMIT.API.WINDOW_MS, 28 windowMs: CONFIG.RATES_LIMIT.API.WINDOW_MS,
31 max: CONFIG.RATES_LIMIT.API.MAX 29 max: CONFIG.RATES_LIMIT.API.MAX
diff --git a/server/controllers/api/jobs.ts b/server/controllers/api/jobs.ts
index 05320311e..13fc04d18 100644
--- a/server/controllers/api/jobs.ts
+++ b/server/controllers/api/jobs.ts
@@ -50,7 +50,7 @@ async function listJobs (req: express.Request, res: express.Response) {
50 }) 50 })
51 const total = await JobQueue.Instance.count(state) 51 const total = await JobQueue.Instance.count(state)
52 52
53 const result: ResultList<any> = { 53 const result: ResultList<Job> = {
54 total, 54 total,
55 data: jobs.map(j => formatJob(j, state)) 55 data: jobs.map(j => formatJob(j, state))
56 } 56 }
diff --git a/server/controllers/api/overviews.ts b/server/controllers/api/overviews.ts
index 46e76ac6b..75f3baedb 100644
--- a/server/controllers/api/overviews.ts
+++ b/server/controllers/api/overviews.ts
@@ -24,7 +24,7 @@ export { overviewsRouter }
24const buildSamples = memoizee(async function () { 24const buildSamples = memoizee(async function () {
25 const [ categories, channels, tags ] = await Promise.all([ 25 const [ categories, channels, tags ] = await Promise.all([
26 VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), 26 VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
27 VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), 27 VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
28 TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT) 28 TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT)
29 ]) 29 ])
30 30
diff --git a/server/controllers/api/server/debug.ts b/server/controllers/api/server/debug.ts
index 4450038f6..e12fc1dd4 100644
--- a/server/controllers/api/server/debug.ts
+++ b/server/controllers/api/server/debug.ts
@@ -1,13 +1,13 @@
1import * as express from 'express' 1import * as express from 'express'
2import { UserRight } from '../../../../shared/models/users' 2import { UserRight } from '../../../../shared/models/users'
3import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' 3import { authenticate, ensureUserHasRight } from '../../../middlewares'
4 4
5const debugRouter = express.Router() 5const debugRouter = express.Router()
6 6
7debugRouter.get('/debug', 7debugRouter.get('/debug',
8 authenticate, 8 authenticate,
9 ensureUserHasRight(UserRight.MANAGE_DEBUG), 9 ensureUserHasRight(UserRight.MANAGE_DEBUG),
10 asyncMiddleware(getDebug) 10 getDebug
11) 11)
12 12
13// --------------------------------------------------------------------------- 13// ---------------------------------------------------------------------------
@@ -18,7 +18,7 @@ export {
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
20 20
21async function getDebug (req: express.Request, res: express.Response) { 21function getDebug (req: express.Request, res: express.Response) {
22 return res.json({ 22 return res.json({
23 ip: req.ip 23 ip: req.ip
24 }).end() 24 }).end()
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index 29a403a43..0bc20bd60 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -24,7 +24,7 @@ import {
24} from '../../../middlewares/validators' 24} from '../../../middlewares/validators'
25import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 25import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
26import { JobQueue } from '../../../lib/job-queue' 26import { JobQueue } from '../../../lib/job-queue'
27import { removeRedundancyOf } from '../../../lib/redundancy' 27import { removeRedundanciesOfServer } from '../../../lib/redundancy'
28import { sequelizeTypescript } from '../../../initializers/database' 28import { sequelizeTypescript } from '../../../initializers/database'
29import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow' 29import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow'
30 30
@@ -135,7 +135,6 @@ async function followInstance (req: express.Request, res: express.Response) {
135 } 135 }
136 136
137 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) 137 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
138 .catch(err => logger.error('Cannot create follow job for %s.', host, err))
139 } 138 }
140 139
141 return res.status(204).end() 140 return res.status(204).end()
@@ -153,7 +152,7 @@ async function removeFollowing (req: express.Request, res: express.Response) {
153 await server.save({ transaction: t }) 152 await server.save({ transaction: t })
154 153
155 // Async, could be long 154 // Async, could be long
156 removeRedundancyOf(server.id) 155 removeRedundanciesOfServer(server.id)
157 .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err)) 156 .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err))
158 157
159 await follow.destroy({ transaction: t }) 158 await follow.destroy({ transaction: t })
diff --git a/server/controllers/api/server/logs.ts b/server/controllers/api/server/logs.ts
index cd1e0f5bf..4b543d686 100644
--- a/server/controllers/api/server/logs.ts
+++ b/server/controllers/api/server/logs.ts
@@ -59,9 +59,9 @@ async function getLogs (req: express.Request, res: express.Response) {
59} 59}
60 60
61async function generateOutput (options: { 61async function generateOutput (options: {
62 startDateQuery: string, 62 startDateQuery: string
63 endDateQuery?: string, 63 endDateQuery?: string
64 level: LogLevel, 64 level: LogLevel
65 nameFilter: RegExp 65 nameFilter: RegExp
66}) { 66}) {
67 const { startDateQuery, level, nameFilter } = options 67 const { startDateQuery, level, nameFilter } = options
@@ -111,7 +111,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
111 const output: any[] = [] 111 const output: any[] = []
112 112
113 for (let i = lines.length - 1; i >= 0; i--) { 113 for (let i = lines.length - 1; i >= 0; i--) {
114 const line = lines[ i ] 114 const line = lines[i]
115 let log: any 115 let log: any
116 116
117 try { 117 try {
@@ -122,7 +122,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
122 } 122 }
123 123
124 logTime = new Date(log.timestamp).getTime() 124 logTime = new Date(log.timestamp).getTime()
125 if (logTime >= startTime && logTime <= endTime && logsLevel[ log.level ] >= logsLevel[ level ]) { 125 if (logTime >= startTime && logTime <= endTime && logsLevel[log.level] >= logsLevel[level]) {
126 output.push(log) 126 output.push(log)
127 127
128 currentSize += line.length 128 currentSize += line.length
diff --git a/server/controllers/api/server/redundancy.ts b/server/controllers/api/server/redundancy.ts
index 4ea6164a3..1ced0759e 100644
--- a/server/controllers/api/server/redundancy.ts
+++ b/server/controllers/api/server/redundancy.ts
@@ -1,9 +1,24 @@
1import * as express from 'express' 1import * as express from 'express'
2import { UserRight } from '../../../../shared/models/users' 2import { UserRight } from '../../../../shared/models/users'
3import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' 3import {
4import { updateServerRedundancyValidator } from '../../../middlewares/validators/redundancy' 4 asyncMiddleware,
5import { removeRedundancyOf } from '../../../lib/redundancy' 5 authenticate,
6 ensureUserHasRight,
7 paginationValidator,
8 setDefaultPagination,
9 setDefaultVideoRedundanciesSort,
10 videoRedundanciesSortValidator
11} from '../../../middlewares'
12import {
13 listVideoRedundanciesValidator,
14 updateServerRedundancyValidator,
15 addVideoRedundancyValidator,
16 removeVideoRedundancyValidator
17} from '../../../middlewares/validators/redundancy'
18import { removeRedundanciesOfServer, removeVideoRedundancy } from '../../../lib/redundancy'
6import { logger } from '../../../helpers/logger' 19import { logger } from '../../../helpers/logger'
20import { VideoRedundancyModel } from '@server/models/redundancy/video-redundancy'
21import { JobQueue } from '@server/lib/job-queue'
7 22
8const serverRedundancyRouter = express.Router() 23const serverRedundancyRouter = express.Router()
9 24
@@ -14,6 +29,31 @@ serverRedundancyRouter.put('/redundancy/:host',
14 asyncMiddleware(updateRedundancy) 29 asyncMiddleware(updateRedundancy)
15) 30)
16 31
32serverRedundancyRouter.get('/redundancy/videos',
33 authenticate,
34 ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES),
35 listVideoRedundanciesValidator,
36 paginationValidator,
37 videoRedundanciesSortValidator,
38 setDefaultVideoRedundanciesSort,
39 setDefaultPagination,
40 asyncMiddleware(listVideoRedundancies)
41)
42
43serverRedundancyRouter.post('/redundancy/videos',
44 authenticate,
45 ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES),
46 addVideoRedundancyValidator,
47 asyncMiddleware(addVideoRedundancy)
48)
49
50serverRedundancyRouter.delete('/redundancy/videos/:redundancyId',
51 authenticate,
52 ensureUserHasRight(UserRight.MANAGE_VIDEOS_REDUNDANCIES),
53 removeVideoRedundancyValidator,
54 asyncMiddleware(removeVideoRedundancyController)
55)
56
17// --------------------------------------------------------------------------- 57// ---------------------------------------------------------------------------
18 58
19export { 59export {
@@ -22,6 +62,42 @@ export {
22 62
23// --------------------------------------------------------------------------- 63// ---------------------------------------------------------------------------
24 64
65async function listVideoRedundancies (req: express.Request, res: express.Response) {
66 const resultList = await VideoRedundancyModel.listForApi({
67 start: req.query.start,
68 count: req.query.count,
69 sort: req.query.sort,
70 target: req.query.target,
71 strategy: req.query.strategy
72 })
73
74 const result = {
75 total: resultList.total,
76 data: resultList.data.map(r => VideoRedundancyModel.toFormattedJSONStatic(r))
77 }
78
79 return res.json(result)
80}
81
82async function addVideoRedundancy (req: express.Request, res: express.Response) {
83 const payload = {
84 videoId: res.locals.onlyVideo.id
85 }
86
87 await JobQueue.Instance.createJobWithPromise({
88 type: 'video-redundancy',
89 payload
90 })
91
92 return res.sendStatus(204)
93}
94
95async function removeVideoRedundancyController (req: express.Request, res: express.Response) {
96 await removeVideoRedundancy(res.locals.videoRedundancy)
97
98 return res.sendStatus(204)
99}
100
25async function updateRedundancy (req: express.Request, res: express.Response) { 101async function updateRedundancy (req: express.Request, res: express.Response) {
26 const server = res.locals.server 102 const server = res.locals.server
27 103
@@ -30,7 +106,7 @@ async function updateRedundancy (req: express.Request, res: express.Response) {
30 await server.save() 106 await server.save()
31 107
32 // Async, could be long 108 // Async, could be long
33 removeRedundancyOf(server.id) 109 removeRedundanciesOfServer(server.id)
34 .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err })) 110 .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err }))
35 111
36 return res.sendStatus(204) 112 return res.sendStatus(204)
diff --git a/server/controllers/api/server/stats.ts b/server/controllers/api/server/stats.ts
index 3616c074d..6d508a481 100644
--- a/server/controllers/api/server/stats.ts
+++ b/server/controllers/api/server/stats.ts
@@ -10,6 +10,7 @@ import { ROUTE_CACHE_LIFETIME } from '../../../initializers/constants'
10import { cacheRoute } from '../../../middlewares/cache' 10import { cacheRoute } from '../../../middlewares/cache'
11import { VideoFileModel } from '../../../models/video/video-file' 11import { VideoFileModel } from '../../../models/video/video-file'
12import { CONFIG } from '../../../initializers/config' 12import { CONFIG } from '../../../initializers/config'
13import { VideoRedundancyStrategyWithManual } from '@shared/models'
13 14
14const statsRouter = express.Router() 15const statsRouter = express.Router()
15 16
@@ -25,8 +26,15 @@ async function getStats (req: express.Request, res: express.Response) {
25 const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats() 26 const { totalInstanceFollowers, totalInstanceFollowing } = await ActorFollowModel.getStats()
26 const { totalLocalVideoFilesSize } = await VideoFileModel.getStats() 27 const { totalLocalVideoFilesSize } = await VideoFileModel.getStats()
27 28
29 const strategies: { strategy: VideoRedundancyStrategyWithManual, size: number }[] = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES
30 .map(r => ({
31 strategy: r.strategy,
32 size: r.size
33 }))
34 strategies.push({ strategy: 'manual', size: null })
35
28 const videosRedundancyStats = await Promise.all( 36 const videosRedundancyStats = await Promise.all(
29 CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.map(r => { 37 strategies.map(r => {
30 return VideoRedundancyModel.getStats(r.strategy) 38 return VideoRedundancyModel.getStats(r.strategy)
31 .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size })) 39 .then(stats => Object.assign(stats, { strategy: r.strategy, totalSize: r.size }))
32 }) 40 })
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts
index b960e80c1..98eb2beed 100644
--- a/server/controllers/api/users/index.ts
+++ b/server/controllers/api/users/index.ts
@@ -2,7 +2,7 @@ import * as express from 'express'
2import * as RateLimit from 'express-rate-limit' 2import * as RateLimit from 'express-rate-limit'
3import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared' 3import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { getFormattedObjects } from '../../../helpers/utils' 5import { generateRandomString, getFormattedObjects } from '../../../helpers/utils'
6import { WEBSERVER } from '../../../initializers/constants' 6import { WEBSERVER } from '../../../initializers/constants'
7import { Emailer } from '../../../lib/emailer' 7import { Emailer } from '../../../lib/emailer'
8import { Redis } from '../../../lib/redis' 8import { Redis } from '../../../lib/redis'
@@ -53,8 +53,6 @@ import { Hooks } from '@server/lib/plugins/hooks'
53 53
54const auditLogger = auditLoggerFactory('users') 54const auditLogger = auditLoggerFactory('users')
55 55
56// FIXME: https://github.com/nfriedly/express-rate-limit/issues/138
57// @ts-ignore
58const loginRateLimiter = RateLimit({ 56const loginRateLimiter = RateLimit({
59 windowMs: CONFIG.RATES_LIMIT.LOGIN.WINDOW_MS, 57 windowMs: CONFIG.RATES_LIMIT.LOGIN.WINDOW_MS,
60 max: CONFIG.RATES_LIMIT.LOGIN.MAX 58 max: CONFIG.RATES_LIMIT.LOGIN.MAX
@@ -199,11 +197,25 @@ async function createUser (req: express.Request, res: express.Response) {
199 adminFlags: body.adminFlags || UserAdminFlag.NONE 197 adminFlags: body.adminFlags || UserAdminFlag.NONE
200 }) as MUser 198 }) as MUser
201 199
200 // NB: due to the validator usersAddValidator, password==='' can only be true if we can send the mail.
201 const createPassword = userToCreate.password === ''
202 if (createPassword) {
203 userToCreate.password = await generateRandomString(20)
204 }
205
202 const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate }) 206 const { user, account, videoChannel } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate })
203 207
204 auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON())) 208 auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()))
205 logger.info('User %s with its channel and account created.', body.username) 209 logger.info('User %s with its channel and account created.', body.username)
206 210
211 if (createPassword) {
212 // this will send an email for newly created users, so then can set their first password.
213 logger.info('Sending to user %s a create password email', body.username)
214 const verificationString = await Redis.Instance.setCreatePasswordVerificationString(user.id)
215 const url = WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString
216 await Emailer.Instance.addPasswordCreateEmailJob(userToCreate.username, user.email, url)
217 }
218
207 Hooks.runAction('action:api.user.created', { body, user, account, videoChannel }) 219 Hooks.runAction('action:api.user.created', { body, user, account, videoChannel })
208 220
209 return res.json({ 221 return res.json({
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
index ac7c62aab..23890e20c 100644
--- a/server/controllers/api/users/me.ts
+++ b/server/controllers/api/users/me.ts
@@ -39,7 +39,7 @@ meRouter.get('/me',
39) 39)
40meRouter.delete('/me', 40meRouter.delete('/me',
41 authenticate, 41 authenticate,
42 asyncMiddleware(deleteMeValidator), 42 deleteMeValidator,
43 asyncMiddleware(deleteMe) 43 asyncMiddleware(deleteMe)
44) 44)
45 45
@@ -214,7 +214,7 @@ async function updateMe (req: express.Request, res: express.Response) {
214} 214}
215 215
216async function updateMyAvatar (req: express.Request, res: express.Response) { 216async function updateMyAvatar (req: express.Request, res: express.Response) {
217 const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] 217 const avatarPhysicalFile = req.files['avatarfile'][0]
218 const user = res.locals.oauth.token.user 218 const user = res.locals.oauth.token.user
219 219
220 const userAccount = await AccountModel.load(user.Account.id) 220 const userAccount = await AccountModel.load(user.Account.id)
diff --git a/server/controllers/api/users/my-subscriptions.ts b/server/controllers/api/users/my-subscriptions.ts
index 43c4c37d8..888392b8b 100644
--- a/server/controllers/api/users/my-subscriptions.ts
+++ b/server/controllers/api/users/my-subscriptions.ts
@@ -19,7 +19,6 @@ import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils'
19import { VideoFilter } from '../../../../shared/models/videos/video-query.type' 19import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
20import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 20import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
21import { JobQueue } from '../../../lib/job-queue' 21import { JobQueue } from '../../../lib/job-queue'
22import { logger } from '../../../helpers/logger'
23import { sequelizeTypescript } from '../../../initializers/database' 22import { sequelizeTypescript } from '../../../initializers/database'
24 23
25const mySubscriptionsRouter = express.Router() 24const mySubscriptionsRouter = express.Router()
@@ -52,7 +51,7 @@ mySubscriptionsRouter.get('/me/subscriptions',
52mySubscriptionsRouter.post('/me/subscriptions', 51mySubscriptionsRouter.post('/me/subscriptions',
53 authenticate, 52 authenticate,
54 userSubscriptionAddValidator, 53 userSubscriptionAddValidator,
55 asyncMiddleware(addUserSubscription) 54 addUserSubscription
56) 55)
57 56
58mySubscriptionsRouter.get('/me/subscriptions/:uri', 57mySubscriptionsRouter.get('/me/subscriptions/:uri',
@@ -106,7 +105,7 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons
106 return res.json(existObject) 105 return res.json(existObject)
107} 106}
108 107
109async function addUserSubscription (req: express.Request, res: express.Response) { 108function addUserSubscription (req: express.Request, res: express.Response) {
110 const user = res.locals.oauth.token.User 109 const user = res.locals.oauth.token.User
111 const [ name, host ] = req.body.uri.split('@') 110 const [ name, host ] = req.body.uri.split('@')
112 111
@@ -117,7 +116,6 @@ async function addUserSubscription (req: express.Request, res: express.Response)
117 } 116 }
118 117
119 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) 118 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
120 .catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err))
121 119
122 return res.status(204).end() 120 return res.status(204).end()
123} 121}
diff --git a/server/controllers/api/video-channel.ts b/server/controllers/api/video-channel.ts
index e1f37a8fb..a808896ff 100644
--- a/server/controllers/api/video-channel.ts
+++ b/server/controllers/api/video-channel.ts
@@ -119,7 +119,7 @@ async function listVideoChannels (req: express.Request, res: express.Response) {
119} 119}
120 120
121async function updateVideoChannelAvatar (req: express.Request, res: express.Response) { 121async function updateVideoChannelAvatar (req: express.Request, res: express.Response) {
122 const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ] 122 const avatarPhysicalFile = req.files['avatarfile'][0]
123 const videoChannel = res.locals.videoChannel 123 const videoChannel = res.locals.videoChannel
124 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) 124 const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON())
125 125
@@ -232,7 +232,6 @@ async function getVideoChannel (req: express.Request, res: express.Response) {
232 232
233 if (videoChannelWithVideos.isOutdated()) { 233 if (videoChannelWithVideos.isOutdated()) {
234 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) 234 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } })
235 .catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err }))
236 } 235 }
237 236
238 return res.json(videoChannelWithVideos.toFormattedJSON()) 237 return res.json(videoChannelWithVideos.toFormattedJSON())
diff --git a/server/controllers/api/video-playlist.ts b/server/controllers/api/video-playlist.ts
index d9f0ff925..b51490bf9 100644
--- a/server/controllers/api/video-playlist.ts
+++ b/server/controllers/api/video-playlist.ts
@@ -144,7 +144,6 @@ function getVideoPlaylist (req: express.Request, res: express.Response) {
144 144
145 if (videoPlaylist.isOutdated()) { 145 if (videoPlaylist.isOutdated()) {
146 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } }) 146 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } })
147 .catch(err => logger.error('Cannot create AP refresher job for playlist %s.', videoPlaylist.url, { err }))
148 } 147 }
149 148
150 return res.json(videoPlaylist.toFormattedJSON()) 149 return res.json(videoPlaylist.toFormattedJSON())
diff --git a/server/controllers/api/videos/captions.ts b/server/controllers/api/videos/captions.ts
index 37481d12f..fd7b165fb 100644
--- a/server/controllers/api/videos/captions.ts
+++ b/server/controllers/api/videos/captions.ts
@@ -66,7 +66,7 @@ async function addVideoCaption (req: express.Request, res: express.Response) {
66 await moveAndProcessCaptionFile(videoCaptionPhysicalFile, videoCaption) 66 await moveAndProcessCaptionFile(videoCaptionPhysicalFile, videoCaption)
67 67
68 await sequelizeTypescript.transaction(async t => { 68 await sequelizeTypescript.transaction(async t => {
69 await VideoCaptionModel.insertOrReplaceLanguage(video.id, req.params.captionLanguage, t) 69 await VideoCaptionModel.insertOrReplaceLanguage(video.id, req.params.captionLanguage, null, t)
70 70
71 // Update video update 71 // Update video update
72 await federateVideoIfNeeded(video, false, t) 72 await federateVideoIfNeeded(video, false, t)
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts
index 28ced5836..ed223cbc9 100644
--- a/server/controllers/api/videos/import.ts
+++ b/server/controllers/api/videos/import.ts
@@ -88,12 +88,12 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
88 const buf = await readFile(torrentfile.path) 88 const buf = await readFile(torrentfile.path)
89 const parsedTorrent = parseTorrent(buf) 89 const parsedTorrent = parseTorrent(buf)
90 90
91 videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[ 0 ] : parsedTorrent.name as string 91 videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name as string
92 } else { 92 } else {
93 magnetUri = body.magnetUri 93 magnetUri = body.magnetUri
94 94
95 const parsed = magnetUtil.decode(magnetUri) 95 const parsed = magnetUtil.decode(magnetUri)
96 videoName = isArray(parsed.name) ? parsed.name[ 0 ] : parsed.name as string 96 videoName = isArray(parsed.name) ? parsed.name[0] : parsed.name as string
97 } 97 }
98 98
99 const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName }) 99 const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName })
@@ -124,7 +124,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
124 videoImportId: videoImport.id, 124 videoImportId: videoImport.id,
125 magnetUri 125 magnetUri
126 } 126 }
127 await JobQueue.Instance.createJob({ type: 'video-import', payload }) 127 await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
128 128
129 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) 129 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
130 130
@@ -176,7 +176,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response)
176 downloadThumbnail: !thumbnailModel, 176 downloadThumbnail: !thumbnailModel,
177 downloadPreview: !previewModel 177 downloadPreview: !previewModel
178 } 178 }
179 await JobQueue.Instance.createJob({ type: 'video-import', payload }) 179 await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
180 180
181 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON())) 181 auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
182 182
@@ -211,7 +211,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You
211async function processThumbnail (req: express.Request, video: VideoModel) { 211async function processThumbnail (req: express.Request, video: VideoModel) {
212 const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined 212 const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined
213 if (thumbnailField) { 213 if (thumbnailField) {
214 const thumbnailPhysicalFile = thumbnailField[ 0 ] 214 const thumbnailPhysicalFile = thumbnailField[0]
215 215
216 return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false) 216 return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false)
217 } 217 }
@@ -231,12 +231,12 @@ async function processPreview (req: express.Request, video: VideoModel) {
231} 231}
232 232
233function insertIntoDB (parameters: { 233function insertIntoDB (parameters: {
234 video: MVideoThumbnailAccountDefault, 234 video: MVideoThumbnailAccountDefault
235 thumbnailModel: MThumbnail, 235 thumbnailModel: MThumbnail
236 previewModel: MThumbnail, 236 previewModel: MThumbnail
237 videoChannel: MChannelAccountDefault, 237 videoChannel: MChannelAccountDefault
238 tags: string[], 238 tags: string[]
239 videoImportAttributes: Partial<MVideoImport>, 239 videoImportAttributes: Partial<MVideoImport>
240 user: MUser 240 user: MUser
241}): Bluebird<MVideoImportFormattable> { 241}): Bluebird<MVideoImportFormattable> {
242 const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters 242 const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 8d4ff07eb..eb46ea01f 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -135,7 +135,7 @@ videosRouter.get('/:id',
135 asyncMiddleware(getVideo) 135 asyncMiddleware(getVideo)
136) 136)
137videosRouter.post('/:id/views', 137videosRouter.post('/:id/views',
138 asyncMiddleware(videosGetValidator), 138 asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')),
139 asyncMiddleware(viewVideo) 139 asyncMiddleware(viewVideo)
140) 140)
141 141
@@ -307,7 +307,7 @@ async function addVideo (req: express.Request, res: express.Response) {
307 } 307 }
308 } 308 }
309 309
310 await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) 310 await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput })
311 } 311 }
312 312
313 Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) 313 Hooks.runAction('action:api.video.uploaded', { video: videoCreated })
@@ -452,14 +452,13 @@ async function getVideo (req: express.Request, res: express.Response) {
452 452
453 if (video.isOutdated()) { 453 if (video.isOutdated()) {
454 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) 454 JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } })
455 .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err }))
456 } 455 }
457 456
458 return res.json(video.toFormattedDetailsJSON()) 457 return res.json(video.toFormattedDetailsJSON())
459} 458}
460 459
461async function viewVideo (req: express.Request, res: express.Response) { 460async function viewVideo (req: express.Request, res: express.Response) {
462 const videoInstance = res.locals.videoAll 461 const videoInstance = res.locals.onlyImmutableVideo
463 462
464 const ip = req.ip 463 const ip = req.ip
465 const exists = await Redis.Instance.doesVideoIPViewExist(ip, videoInstance.uuid) 464 const exists = await Redis.Instance.doesVideoIPViewExist(ip, videoInstance.uuid)
diff --git a/server/controllers/client.ts b/server/controllers/client.ts
index dc3ff18fc..e4643e171 100644
--- a/server/controllers/client.ts
+++ b/server/controllers/client.ts
@@ -66,7 +66,7 @@ export {
66 66
67// --------------------------------------------------------------------------- 67// ---------------------------------------------------------------------------
68 68
69async function serveServerTranslations (req: express.Request, res: express.Response) { 69function serveServerTranslations (req: express.Request, res: express.Response) {
70 const locale = req.params.locale 70 const locale = req.params.locale
71 const file = req.params.file 71 const file = req.params.file
72 72
diff --git a/server/controllers/static.ts b/server/controllers/static.ts
index a4bb3a4d9..271b788f6 100644
--- a/server/controllers/static.ts
+++ b/server/controllers/static.ts
@@ -1,15 +1,15 @@
1import * as cors from 'cors' 1import * as cors from 'cors'
2import * as express from 'express' 2import * as express from 'express'
3import { 3import {
4 CONSTRAINTS_FIELDS,
5 DEFAULT_THEME_NAME,
4 HLS_STREAMING_PLAYLIST_DIRECTORY, 6 HLS_STREAMING_PLAYLIST_DIRECTORY,
5 PEERTUBE_VERSION, 7 PEERTUBE_VERSION,
6 ROUTE_CACHE_LIFETIME, 8 ROUTE_CACHE_LIFETIME,
7 STATIC_DOWNLOAD_PATHS, 9 STATIC_DOWNLOAD_PATHS,
8 STATIC_MAX_AGE, 10 STATIC_MAX_AGE,
9 STATIC_PATHS, 11 STATIC_PATHS,
10 WEBSERVER, 12 WEBSERVER
11 CONSTRAINTS_FIELDS,
12 DEFAULT_THEME_NAME
13} from '../initializers/constants' 13} from '../initializers/constants'
14import { cacheRoute } from '../middlewares/cache' 14import { cacheRoute } from '../middlewares/cache'
15import { asyncMiddleware, videosDownloadValidator } from '../middlewares' 15import { asyncMiddleware, videosDownloadValidator } from '../middlewares'
@@ -19,8 +19,7 @@ import { VideoCommentModel } from '../models/video/video-comment'
19import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo' 19import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo'
20import { join } from 'path' 20import { join } from 'path'
21import { root } from '../helpers/core-utils' 21import { root } from '../helpers/core-utils'
22import { CONFIG } from '../initializers/config' 22import { CONFIG, isEmailEnabled } from '../initializers/config'
23import { Emailer } from '../lib/emailer'
24import { getPreview, getVideoCaption } from './lazy-static' 23import { getPreview, getVideoCaption } from './lazy-static'
25import { VideoStreamingPlaylistType } from '@shared/models/videos/video-streaming-playlist.type' 24import { VideoStreamingPlaylistType } from '@shared/models/videos/video-streaming-playlist.type'
26import { MVideoFile, MVideoFullLight } from '@server/typings/models' 25import { MVideoFile, MVideoFullLight } from '@server/typings/models'
@@ -45,12 +44,12 @@ staticRouter.use(
45staticRouter.use( 44staticRouter.use(
46 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', 45 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent',
47 asyncMiddleware(videosDownloadValidator), 46 asyncMiddleware(videosDownloadValidator),
48 asyncMiddleware(downloadTorrent) 47 downloadTorrent
49) 48)
50staticRouter.use( 49staticRouter.use(
51 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', 50 STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent',
52 asyncMiddleware(videosDownloadValidator), 51 asyncMiddleware(videosDownloadValidator),
53 asyncMiddleware(downloadHLSVideoFileTorrent) 52 downloadHLSVideoFileTorrent
54) 53)
55 54
56// Videos path for webseeding 55// Videos path for webseeding
@@ -68,13 +67,13 @@ staticRouter.use(
68staticRouter.use( 67staticRouter.use(
69 STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', 68 STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension',
70 asyncMiddleware(videosDownloadValidator), 69 asyncMiddleware(videosDownloadValidator),
71 asyncMiddleware(downloadVideoFile) 70 downloadVideoFile
72) 71)
73 72
74staticRouter.use( 73staticRouter.use(
75 STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', 74 STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension',
76 asyncMiddleware(videosDownloadValidator), 75 asyncMiddleware(videosDownloadValidator),
77 asyncMiddleware(downloadHLSVideoFile) 76 downloadHLSVideoFile
78) 77)
79 78
80// HLS 79// HLS
@@ -235,6 +234,12 @@ async function generateNodeinfo (req: express.Request, res: express.Response) {
235 nodeName: CONFIG.INSTANCE.NAME, 234 nodeName: CONFIG.INSTANCE.NAME,
236 nodeDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, 235 nodeDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION,
237 nodeConfig: { 236 nodeConfig: {
237 search: {
238 remoteUri: {
239 users: CONFIG.SEARCH.REMOTE_URI.USERS,
240 anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
241 }
242 },
238 plugin: { 243 plugin: {
239 registered: getRegisteredPlugins() 244 registered: getRegisteredPlugins()
240 }, 245 },
@@ -243,7 +248,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) {
243 default: getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) 248 default: getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
244 }, 249 },
245 email: { 250 email: {
246 enabled: Emailer.isEnabled() 251 enabled: isEmailEnabled()
247 }, 252 },
248 contactForm: { 253 contactForm: {
249 enabled: CONFIG.CONTACT_FORM.ENABLED 254 enabled: CONFIG.CONTACT_FORM.ENABLED
@@ -325,7 +330,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) {
325 return res.send(json).end() 330 return res.send(json).end()
326} 331}
327 332
328async function downloadTorrent (req: express.Request, res: express.Response) { 333function downloadTorrent (req: express.Request, res: express.Response) {
329 const video = res.locals.videoAll 334 const video = res.locals.videoAll
330 335
331 const videoFile = getVideoFile(req, video.VideoFiles) 336 const videoFile = getVideoFile(req, video.VideoFiles)
@@ -334,7 +339,7 @@ async function downloadTorrent (req: express.Request, res: express.Response) {
334 return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) 339 return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`)
335} 340}
336 341
337async function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) { 342function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) {
338 const video = res.locals.videoAll 343 const video = res.locals.videoAll
339 344
340 const playlist = getHLSPlaylist(video) 345 const playlist = getHLSPlaylist(video)
@@ -346,7 +351,7 @@ async function downloadHLSVideoFileTorrent (req: express.Request, res: express.R
346 return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) 351 return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`)
347} 352}
348 353
349async function downloadVideoFile (req: express.Request, res: express.Response) { 354function downloadVideoFile (req: express.Request, res: express.Response) {
350 const video = res.locals.videoAll 355 const video = res.locals.videoAll
351 356
352 const videoFile = getVideoFile(req, video.VideoFiles) 357 const videoFile = getVideoFile(req, video.VideoFiles)
@@ -355,7 +360,7 @@ async function downloadVideoFile (req: express.Request, res: express.Response) {
355 return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) 360 return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`)
356} 361}
357 362
358async function downloadHLSVideoFile (req: express.Request, res: express.Response) { 363function downloadHLSVideoFile (req: express.Request, res: express.Response) {
359 const video = res.locals.videoAll 364 const video = res.locals.videoAll
360 const playlist = getHLSPlaylist(video) 365 const playlist = getHLSPlaylist(video)
361 if (!playlist) return res.status(404).end 366 if (!playlist) return res.status(404).end
diff --git a/server/controllers/tracker.ts b/server/controllers/tracker.ts
index 2ae1cf86c..e9c8a13da 100644
--- a/server/controllers/tracker.ts
+++ b/server/controllers/tracker.ts
@@ -6,7 +6,6 @@ import * as proxyAddr from 'proxy-addr'
6import { Server as WebSocketServer } from 'ws' 6import { Server as WebSocketServer } from 'ws'
7import { TRACKER_RATE_LIMITS } from '../initializers/constants' 7import { TRACKER_RATE_LIMITS } from '../initializers/constants'
8import { VideoFileModel } from '../models/video/video-file' 8import { VideoFileModel } from '../models/video/video-file'
9import { parse } from 'url'
10import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' 9import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
11import { CONFIG } from '../initializers/config' 10import { CONFIG } from '../initializers/config'
12 11
@@ -38,11 +37,11 @@ const trackerServer = new TrackerServer({
38 37
39 const key = ip + '-' + infoHash 38 const key = ip + '-' + infoHash
40 39
41 peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1 40 peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1
42 peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1 41 peersIpInfoHash[key] = peersIpInfoHash[key] ? peersIpInfoHash[key] + 1 : 1
43 42
44 if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) { 43 if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[key] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
45 return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`)) 44 return cb(new Error(`Too many requests (${peersIpInfoHash[key]} of ip ${ip} for torrent ${infoHash}`))
46 } 45 }
47 46
48 try { 47 try {
@@ -87,10 +86,8 @@ function createWebsocketTrackerServer (app: express.Application) {
87 trackerServer.onWebSocketConnection(ws) 86 trackerServer.onWebSocketConnection(ws)
88 }) 87 })
89 88
90 server.on('upgrade', (request, socket, head) => { 89 server.on('upgrade', (request: express.Request, socket, head) => {
91 const pathname = parse(request.url).pathname 90 if (request.path === '/tracker/socket') {
92
93 if (pathname === '/tracker/socket') {
94 wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request)) 91 wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request))
95 } 92 }
96 93
diff --git a/server/controllers/webfinger.ts b/server/controllers/webfinger.ts
index fc9575160..77c851880 100644
--- a/server/controllers/webfinger.ts
+++ b/server/controllers/webfinger.ts
@@ -18,7 +18,7 @@ export {
18// --------------------------------------------------------------------------- 18// ---------------------------------------------------------------------------
19 19
20function webfingerController (req: express.Request, res: express.Response) { 20function webfingerController (req: express.Request, res: express.Response) {
21 const actor = res.locals.actorFull 21 const actor = res.locals.actorUrl
22 22
23 const json = { 23 const json = {
24 subject: req.query.resource, 24 subject: req.query.resource,
@@ -32,5 +32,5 @@ function webfingerController (req: express.Request, res: express.Response) {
32 ] 32 ]
33 } 33 }
34 34
35 return res.json(json).end() 35 return res.json(json)
36} 36}