diff options
Diffstat (limited to 'server')
27 files changed, 229 insertions, 96 deletions
diff --git a/server/controllers/api/videos/token.ts b/server/controllers/api/videos/token.ts index 009b6dfb6..22387c3e8 100644 --- a/server/controllers/api/videos/token.ts +++ b/server/controllers/api/videos/token.ts | |||
@@ -22,7 +22,7 @@ export { | |||
22 | function generateToken (req: express.Request, res: express.Response) { | 22 | function generateToken (req: express.Request, res: express.Response) { |
23 | const video = res.locals.onlyVideo | 23 | const video = res.locals.onlyVideo |
24 | 24 | ||
25 | const { token, expires } = VideoTokensManager.Instance.create(video.uuid) | 25 | const { token, expires } = VideoTokensManager.Instance.create({ videoUUID: video.uuid, user: res.locals.oauth.token.User }) |
26 | 26 | ||
27 | return res.json({ | 27 | return res.json({ |
28 | files: { | 28 | files: { |
diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts index 772fe734d..ef810a842 100644 --- a/server/controllers/feeds.ts +++ b/server/controllers/feeds.ts | |||
@@ -285,8 +285,8 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) { | |||
285 | content: toSafeHtml(video.description), | 285 | content: toSafeHtml(video.description), |
286 | author: [ | 286 | author: [ |
287 | { | 287 | { |
288 | name: video.VideoChannel.Account.getDisplayName(), | 288 | name: video.VideoChannel.getDisplayName(), |
289 | link: video.VideoChannel.Account.Actor.url | 289 | link: video.VideoChannel.Actor.url |
290 | } | 290 | } |
291 | ], | 291 | ], |
292 | date: video.publishedAt, | 292 | date: video.publishedAt, |
diff --git a/server/controllers/tracker.ts b/server/controllers/tracker.ts index 19a8b2bc9..c4f3a8889 100644 --- a/server/controllers/tracker.ts +++ b/server/controllers/tracker.ts | |||
@@ -1,17 +1,22 @@ | |||
1 | import { Server as TrackerServer } from 'bittorrent-tracker' | 1 | import { Server as TrackerServer } from 'bittorrent-tracker' |
2 | import express from 'express' | 2 | import express from 'express' |
3 | import { createServer } from 'http' | 3 | import { createServer } from 'http' |
4 | import LRUCache from 'lru-cache' | ||
4 | import proxyAddr from 'proxy-addr' | 5 | import proxyAddr from 'proxy-addr' |
5 | import { WebSocketServer } from 'ws' | 6 | import { WebSocketServer } from 'ws' |
6 | import { Redis } from '@server/lib/redis' | ||
7 | import { logger } from '../helpers/logger' | 7 | import { logger } from '../helpers/logger' |
8 | import { CONFIG } from '../initializers/config' | 8 | import { CONFIG } from '../initializers/config' |
9 | import { TRACKER_RATE_LIMITS } from '../initializers/constants' | 9 | import { LRU_CACHE, TRACKER_RATE_LIMITS } from '../initializers/constants' |
10 | import { VideoFileModel } from '../models/video/video-file' | 10 | import { VideoFileModel } from '../models/video/video-file' |
11 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' | 11 | import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' |
12 | 12 | ||
13 | const trackerRouter = express.Router() | 13 | const trackerRouter = express.Router() |
14 | 14 | ||
15 | const blockedIPs = new LRUCache<string, boolean>({ | ||
16 | max: LRU_CACHE.TRACKER_IPS.MAX_SIZE, | ||
17 | ttl: TRACKER_RATE_LIMITS.BLOCK_IP_LIFETIME | ||
18 | }) | ||
19 | |||
15 | let peersIps = {} | 20 | let peersIps = {} |
16 | let peersIpInfoHash = {} | 21 | let peersIpInfoHash = {} |
17 | runPeersChecker() | 22 | runPeersChecker() |
@@ -55,8 +60,7 @@ const trackerServer = new TrackerServer({ | |||
55 | 60 | ||
56 | // Close socket connection and block IP for a few time | 61 | // Close socket connection and block IP for a few time |
57 | if (params.type === 'ws') { | 62 | if (params.type === 'ws') { |
58 | Redis.Instance.setTrackerBlockIP(ip) | 63 | blockedIPs.set(ip, true) |
59 | .catch(err => logger.error('Cannot set tracker block ip.', { err })) | ||
60 | 64 | ||
61 | // setTimeout to wait filter response | 65 | // setTimeout to wait filter response |
62 | setTimeout(() => params.socket.close(), 0) | 66 | setTimeout(() => params.socket.close(), 0) |
@@ -102,26 +106,22 @@ function createWebsocketTrackerServer (app: express.Application) { | |||
102 | if (request.url === '/tracker/socket') { | 106 | if (request.url === '/tracker/socket') { |
103 | const ip = proxyAddr(request, CONFIG.TRUST_PROXY) | 107 | const ip = proxyAddr(request, CONFIG.TRUST_PROXY) |
104 | 108 | ||
105 | Redis.Instance.doesTrackerBlockIPExist(ip) | 109 | if (blockedIPs.has(ip)) { |
106 | .then(result => { | 110 | logger.debug('Blocking IP %s from tracker.', ip) |
107 | if (result === true) { | ||
108 | logger.debug('Blocking IP %s from tracker.', ip) | ||
109 | 111 | ||
110 | socket.write('HTTP/1.1 403 Forbidden\r\n\r\n') | 112 | socket.write('HTTP/1.1 403 Forbidden\r\n\r\n') |
111 | socket.destroy() | 113 | socket.destroy() |
112 | return | 114 | return |
113 | } | 115 | } |
114 | 116 | ||
115 | // FIXME: typings | 117 | // FIXME: typings |
116 | return wss.handleUpgrade(request, socket as any, head, ws => wss.emit('connection', ws, request)) | 118 | return wss.handleUpgrade(request, socket as any, head, ws => wss.emit('connection', ws, request)) |
117 | }) | ||
118 | .catch(err => logger.error('Cannot check if tracker block ip exists.', { err })) | ||
119 | } | 119 | } |
120 | 120 | ||
121 | // Don't destroy socket, we have Socket.IO too | 121 | // Don't destroy socket, we have Socket.IO too |
122 | }) | 122 | }) |
123 | 123 | ||
124 | return server | 124 | return { server, trackerServer } |
125 | } | 125 | } |
126 | 126 | ||
127 | // --------------------------------------------------------------------------- | 127 | // --------------------------------------------------------------------------- |
diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index 3dc5504e3..b3ab3ac64 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts | |||
@@ -103,7 +103,13 @@ function checkMimetypeRegex (fileMimeType: string, mimeTypeRegex: string) { | |||
103 | // --------------------------------------------------------------------------- | 103 | // --------------------------------------------------------------------------- |
104 | 104 | ||
105 | function toCompleteUUID (value: string) { | 105 | function toCompleteUUID (value: string) { |
106 | if (isShortUUID(value)) return shortToUUID(value) | 106 | if (isShortUUID(value)) { |
107 | try { | ||
108 | return shortToUUID(value) | ||
109 | } catch { | ||
110 | return null | ||
111 | } | ||
112 | } | ||
107 | 113 | ||
108 | return value | 114 | return value |
109 | } | 115 | } |
diff --git a/server/helpers/youtube-dl/youtube-dl-cli.ts b/server/helpers/youtube-dl/youtube-dl-cli.ts index a2f630953..765038cea 100644 --- a/server/helpers/youtube-dl/youtube-dl-cli.ts +++ b/server/helpers/youtube-dl/youtube-dl-cli.ts | |||
@@ -6,6 +6,7 @@ import { VideoResolution } from '@shared/models' | |||
6 | import { logger, loggerTagsFactory } from '../logger' | 6 | import { logger, loggerTagsFactory } from '../logger' |
7 | import { getProxy, isProxyEnabled } from '../proxy' | 7 | import { getProxy, isProxyEnabled } from '../proxy' |
8 | import { isBinaryResponse, peertubeGot } from '../requests' | 8 | import { isBinaryResponse, peertubeGot } from '../requests' |
9 | import { OptionsOfBufferResponseBody } from 'got/dist/source' | ||
9 | 10 | ||
10 | const lTags = loggerTagsFactory('youtube-dl') | 11 | const lTags = loggerTagsFactory('youtube-dl') |
11 | 12 | ||
@@ -28,7 +29,16 @@ export class YoutubeDLCLI { | |||
28 | 29 | ||
29 | logger.info('Updating youtubeDL binary from %s.', url, lTags()) | 30 | logger.info('Updating youtubeDL binary from %s.', url, lTags()) |
30 | 31 | ||
31 | const gotOptions = { context: { bodyKBLimit: 20_000 }, responseType: 'buffer' as 'buffer' } | 32 | const gotOptions: OptionsOfBufferResponseBody = { |
33 | context: { bodyKBLimit: 20_000 }, | ||
34 | responseType: 'buffer' as 'buffer' | ||
35 | } | ||
36 | |||
37 | if (process.env.YOUTUBE_DL_DOWNLOAD_BEARER_TOKEN) { | ||
38 | gotOptions.headers = { | ||
39 | authorization: 'Bearer ' + process.env.YOUTUBE_DL_DOWNLOAD_BEARER_TOKEN | ||
40 | } | ||
41 | } | ||
32 | 42 | ||
33 | try { | 43 | try { |
34 | let gotResult = await peertubeGot(url, gotOptions) | 44 | let gotResult = await peertubeGot(url, gotOptions) |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 0e56f0c9f..ec5045078 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -781,6 +781,9 @@ const LRU_CACHE = { | |||
781 | VIDEO_TOKENS: { | 781 | VIDEO_TOKENS: { |
782 | MAX_SIZE: 100_000, | 782 | MAX_SIZE: 100_000, |
783 | TTL: parseDurationToMs('8 hours') | 783 | TTL: parseDurationToMs('8 hours') |
784 | }, | ||
785 | TRACKER_IPS: { | ||
786 | MAX_SIZE: 100_000 | ||
784 | } | 787 | } |
785 | } | 788 | } |
786 | 789 | ||
@@ -884,7 +887,7 @@ const TRACKER_RATE_LIMITS = { | |||
884 | INTERVAL: 60000 * 5, // 5 minutes | 887 | INTERVAL: 60000 * 5, // 5 minutes |
885 | ANNOUNCES_PER_IP_PER_INFOHASH: 15, // maximum announces per torrent in the interval | 888 | ANNOUNCES_PER_IP_PER_INFOHASH: 15, // maximum announces per torrent in the interval |
886 | ANNOUNCES_PER_IP: 30, // maximum announces for all our torrents in the interval | 889 | ANNOUNCES_PER_IP: 30, // maximum announces for all our torrents in the interval |
887 | BLOCK_IP_LIFETIME: 60000 * 3 // 3 minutes | 890 | BLOCK_IP_LIFETIME: parseDurationToMs('3 minutes') |
888 | } | 891 | } |
889 | 892 | ||
890 | const P2P_MEDIA_LOADER_PEER_VERSION = 2 | 893 | const P2P_MEDIA_LOADER_PEER_VERSION = 2 |
diff --git a/server/lib/opentelemetry/metric-helpers/bittorrent-tracker-observers-builder.ts b/server/lib/opentelemetry/metric-helpers/bittorrent-tracker-observers-builder.ts new file mode 100644 index 000000000..ef40c0fa9 --- /dev/null +++ b/server/lib/opentelemetry/metric-helpers/bittorrent-tracker-observers-builder.ts | |||
@@ -0,0 +1,51 @@ | |||
1 | import { Meter } from '@opentelemetry/api' | ||
2 | |||
3 | export class BittorrentTrackerObserversBuilder { | ||
4 | |||
5 | constructor (private readonly meter: Meter, private readonly trackerServer: any) { | ||
6 | |||
7 | } | ||
8 | |||
9 | buildObservers () { | ||
10 | const activeInfohashes = this.meter.createObservableGauge('peertube_bittorrent_tracker_active_infohashes_total', { | ||
11 | description: 'Total active infohashes in the PeerTube BitTorrent Tracker' | ||
12 | }) | ||
13 | const inactiveInfohashes = this.meter.createObservableGauge('peertube_bittorrent_tracker_inactive_infohashes_total', { | ||
14 | description: 'Total inactive infohashes in the PeerTube BitTorrent Tracker' | ||
15 | }) | ||
16 | const peers = this.meter.createObservableGauge('peertube_bittorrent_tracker_peers_total', { | ||
17 | description: 'Total peers in the PeerTube BitTorrent Tracker' | ||
18 | }) | ||
19 | |||
20 | this.meter.addBatchObservableCallback(observableResult => { | ||
21 | const infohashes = Object.keys(this.trackerServer.torrents) | ||
22 | |||
23 | const counters = { | ||
24 | activeInfohashes: 0, | ||
25 | inactiveInfohashes: 0, | ||
26 | peers: 0, | ||
27 | uncompletedPeers: 0 | ||
28 | } | ||
29 | |||
30 | for (const infohash of infohashes) { | ||
31 | const content = this.trackerServer.torrents[infohash] | ||
32 | |||
33 | const peers = content.peers | ||
34 | if (peers.keys.length !== 0) counters.activeInfohashes++ | ||
35 | else counters.inactiveInfohashes++ | ||
36 | |||
37 | for (const peerId of peers.keys) { | ||
38 | const peer = peers.peek(peerId) | ||
39 | if (peer == null) return | ||
40 | |||
41 | counters.peers++ | ||
42 | } | ||
43 | } | ||
44 | |||
45 | observableResult.observe(activeInfohashes, counters.activeInfohashes) | ||
46 | observableResult.observe(inactiveInfohashes, counters.inactiveInfohashes) | ||
47 | observableResult.observe(peers, counters.peers) | ||
48 | }, [ activeInfohashes, inactiveInfohashes, peers ]) | ||
49 | } | ||
50 | |||
51 | } | ||
diff --git a/server/lib/opentelemetry/metric-helpers/index.ts b/server/lib/opentelemetry/metric-helpers/index.ts index 775d954ba..47b24a54f 100644 --- a/server/lib/opentelemetry/metric-helpers/index.ts +++ b/server/lib/opentelemetry/metric-helpers/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | export * from './bittorrent-tracker-observers-builder' | ||
1 | export * from './lives-observers-builder' | 2 | export * from './lives-observers-builder' |
2 | export * from './job-queue-observers-builder' | 3 | export * from './job-queue-observers-builder' |
3 | export * from './nodejs-observers-builder' | 4 | export * from './nodejs-observers-builder' |
diff --git a/server/lib/opentelemetry/metrics.ts b/server/lib/opentelemetry/metrics.ts index 226d514c0..9cc067e4a 100644 --- a/server/lib/opentelemetry/metrics.ts +++ b/server/lib/opentelemetry/metrics.ts | |||
@@ -7,6 +7,7 @@ import { CONFIG } from '@server/initializers/config' | |||
7 | import { MVideoImmutable } from '@server/types/models' | 7 | import { MVideoImmutable } from '@server/types/models' |
8 | import { PlaybackMetricCreate } from '@shared/models' | 8 | import { PlaybackMetricCreate } from '@shared/models' |
9 | import { | 9 | import { |
10 | BittorrentTrackerObserversBuilder, | ||
10 | JobQueueObserversBuilder, | 11 | JobQueueObserversBuilder, |
11 | LivesObserversBuilder, | 12 | LivesObserversBuilder, |
12 | NodeJSObserversBuilder, | 13 | NodeJSObserversBuilder, |
@@ -41,7 +42,7 @@ class OpenTelemetryMetrics { | |||
41 | }) | 42 | }) |
42 | } | 43 | } |
43 | 44 | ||
44 | registerMetrics () { | 45 | registerMetrics (options: { trackerServer: any }) { |
45 | if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return | 46 | if (CONFIG.OPEN_TELEMETRY.METRICS.ENABLED !== true) return |
46 | 47 | ||
47 | logger.info('Registering Open Telemetry metrics') | 48 | logger.info('Registering Open Telemetry metrics') |
@@ -80,6 +81,9 @@ class OpenTelemetryMetrics { | |||
80 | 81 | ||
81 | const viewersObserversBuilder = new ViewersObserversBuilder(this.meter) | 82 | const viewersObserversBuilder = new ViewersObserversBuilder(this.meter) |
82 | viewersObserversBuilder.buildObservers() | 83 | viewersObserversBuilder.buildObservers() |
84 | |||
85 | const bittorrentTrackerObserversBuilder = new BittorrentTrackerObserversBuilder(this.meter, options.trackerServer) | ||
86 | bittorrentTrackerObserversBuilder.buildObservers() | ||
83 | } | 87 | } |
84 | 88 | ||
85 | observePlaybackMetric (video: MVideoImmutable, metrics: PlaybackMetricCreate) { | 89 | observePlaybackMetric (video: MVideoImmutable, metrics: PlaybackMetricCreate) { |
diff --git a/server/lib/plugins/plugin-helpers-builder.ts b/server/lib/plugins/plugin-helpers-builder.ts index 7b1def6e3..66383af46 100644 --- a/server/lib/plugins/plugin-helpers-builder.ts +++ b/server/lib/plugins/plugin-helpers-builder.ts | |||
@@ -209,6 +209,10 @@ function buildConfigHelpers () { | |||
209 | return WEBSERVER.URL | 209 | return WEBSERVER.URL |
210 | }, | 210 | }, |
211 | 211 | ||
212 | getServerListeningConfig () { | ||
213 | return { hostname: CONFIG.LISTEN.HOSTNAME, port: CONFIG.LISTEN.PORT } | ||
214 | }, | ||
215 | |||
212 | getServerConfig () { | 216 | getServerConfig () { |
213 | return ServerConfigManager.Instance.getServerConfig() | 217 | return ServerConfigManager.Instance.getServerConfig() |
214 | } | 218 | } |
@@ -245,7 +249,7 @@ function buildUserHelpers () { | |||
245 | }, | 249 | }, |
246 | 250 | ||
247 | getAuthUser: (res: express.Response) => { | 251 | getAuthUser: (res: express.Response) => { |
248 | const user = res.locals.oauth?.token?.User | 252 | const user = res.locals.oauth?.token?.User || res.locals.videoFileToken?.user |
249 | if (!user) return undefined | 253 | if (!user) return undefined |
250 | 254 | ||
251 | return UserModel.loadByIdFull(user.id) | 255 | return UserModel.loadByIdFull(user.id) |
diff --git a/server/lib/redis.ts b/server/lib/redis.ts index c0e9aece7..451ddd0b6 100644 --- a/server/lib/redis.ts +++ b/server/lib/redis.ts | |||
@@ -8,7 +8,6 @@ import { | |||
8 | AP_CLEANER, | 8 | AP_CLEANER, |
9 | CONTACT_FORM_LIFETIME, | 9 | CONTACT_FORM_LIFETIME, |
10 | RESUMABLE_UPLOAD_SESSION_LIFETIME, | 10 | RESUMABLE_UPLOAD_SESSION_LIFETIME, |
11 | TRACKER_RATE_LIMITS, | ||
12 | TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME, | 11 | TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME, |
13 | USER_EMAIL_VERIFY_LIFETIME, | 12 | USER_EMAIL_VERIFY_LIFETIME, |
14 | USER_PASSWORD_CREATE_LIFETIME, | 13 | USER_PASSWORD_CREATE_LIFETIME, |
@@ -157,16 +156,6 @@ class Redis { | |||
157 | return this.exists(this.generateIPViewKey(ip, videoUUID)) | 156 | return this.exists(this.generateIPViewKey(ip, videoUUID)) |
158 | } | 157 | } |
159 | 158 | ||
160 | /* ************ Tracker IP block ************ */ | ||
161 | |||
162 | setTrackerBlockIP (ip: string) { | ||
163 | return this.setValue(this.generateTrackerBlockIPKey(ip), '1', TRACKER_RATE_LIMITS.BLOCK_IP_LIFETIME) | ||
164 | } | ||
165 | |||
166 | async doesTrackerBlockIPExist (ip: string) { | ||
167 | return this.exists(this.generateTrackerBlockIPKey(ip)) | ||
168 | } | ||
169 | |||
170 | /* ************ Video views stats ************ */ | 159 | /* ************ Video views stats ************ */ |
171 | 160 | ||
172 | addVideoViewStats (videoId: number) { | 161 | addVideoViewStats (videoId: number) { |
@@ -365,10 +354,6 @@ class Redis { | |||
365 | return `views-${videoUUID}-${ip}` | 354 | return `views-${videoUUID}-${ip}` |
366 | } | 355 | } |
367 | 356 | ||
368 | private generateTrackerBlockIPKey (ip: string) { | ||
369 | return `tracker-block-ip-${ip}` | ||
370 | } | ||
371 | |||
372 | private generateContactFormKey (ip: string) { | 357 | private generateContactFormKey (ip: string) { |
373 | return 'contact-form-' + ip | 358 | return 'contact-form-' + ip |
374 | } | 359 | } |
diff --git a/server/lib/sync-channel.ts b/server/lib/sync-channel.ts index 10167ee38..3a805a943 100644 --- a/server/lib/sync-channel.ts +++ b/server/lib/sync-channel.ts | |||
@@ -76,7 +76,7 @@ export async function synchronizeChannel (options: { | |||
76 | 76 | ||
77 | await JobQueue.Instance.createJobWithChildren(parent, children) | 77 | await JobQueue.Instance.createJobWithChildren(parent, children) |
78 | } catch (err) { | 78 | } catch (err) { |
79 | logger.error(`Failed to import channel ${channel.name}`, { err }) | 79 | logger.error(`Failed to import ${externalChannelUrl} in channel ${channel.name}`, { err }) |
80 | channelSync.state = VideoChannelSyncState.FAILED | 80 | channelSync.state = VideoChannelSyncState.FAILED |
81 | await channelSync.save() | 81 | await channelSync.save() |
82 | } | 82 | } |
diff --git a/server/lib/video-tokens-manager.ts b/server/lib/video-tokens-manager.ts index c43085d16..17aa29cdd 100644 --- a/server/lib/video-tokens-manager.ts +++ b/server/lib/video-tokens-manager.ts | |||
@@ -1,5 +1,7 @@ | |||
1 | import LRUCache from 'lru-cache' | 1 | import LRUCache from 'lru-cache' |
2 | import { LRU_CACHE } from '@server/initializers/constants' | 2 | import { LRU_CACHE } from '@server/initializers/constants' |
3 | import { MUserAccountUrl } from '@server/types/models' | ||
4 | import { pick } from '@shared/core-utils' | ||
3 | import { buildUUID } from '@shared/extra-utils' | 5 | import { buildUUID } from '@shared/extra-utils' |
4 | 6 | ||
5 | // --------------------------------------------------------------------------- | 7 | // --------------------------------------------------------------------------- |
@@ -10,19 +12,22 @@ class VideoTokensManager { | |||
10 | 12 | ||
11 | private static instance: VideoTokensManager | 13 | private static instance: VideoTokensManager |
12 | 14 | ||
13 | private readonly lruCache = new LRUCache<string, string>({ | 15 | private readonly lruCache = new LRUCache<string, { videoUUID: string, user: MUserAccountUrl }>({ |
14 | max: LRU_CACHE.VIDEO_TOKENS.MAX_SIZE, | 16 | max: LRU_CACHE.VIDEO_TOKENS.MAX_SIZE, |
15 | ttl: LRU_CACHE.VIDEO_TOKENS.TTL | 17 | ttl: LRU_CACHE.VIDEO_TOKENS.TTL |
16 | }) | 18 | }) |
17 | 19 | ||
18 | private constructor () {} | 20 | private constructor () {} |
19 | 21 | ||
20 | create (videoUUID: string) { | 22 | create (options: { |
23 | user: MUserAccountUrl | ||
24 | videoUUID: string | ||
25 | }) { | ||
21 | const token = buildUUID() | 26 | const token = buildUUID() |
22 | 27 | ||
23 | const expires = new Date(new Date().getTime() + LRU_CACHE.VIDEO_TOKENS.TTL) | 28 | const expires = new Date(new Date().getTime() + LRU_CACHE.VIDEO_TOKENS.TTL) |
24 | 29 | ||
25 | this.lruCache.set(token, videoUUID) | 30 | this.lruCache.set(token, pick(options, [ 'user', 'videoUUID' ])) |
26 | 31 | ||
27 | return { token, expires } | 32 | return { token, expires } |
28 | } | 33 | } |
@@ -34,7 +39,16 @@ class VideoTokensManager { | |||
34 | const value = this.lruCache.get(options.token) | 39 | const value = this.lruCache.get(options.token) |
35 | if (!value) return false | 40 | if (!value) return false |
36 | 41 | ||
37 | return value === options.videoUUID | 42 | return value.videoUUID === options.videoUUID |
43 | } | ||
44 | |||
45 | getUserFromToken (options: { | ||
46 | token: string | ||
47 | }) { | ||
48 | const value = this.lruCache.get(options.token) | ||
49 | if (!value) return undefined | ||
50 | |||
51 | return value.user | ||
38 | } | 52 | } |
39 | 53 | ||
40 | static get Instance () { | 54 | static get Instance () { |
diff --git a/server/middlewares/validators/shared/videos.ts b/server/middlewares/validators/shared/videos.ts index ebbfc0a0a..0033a32ff 100644 --- a/server/middlewares/validators/shared/videos.ts +++ b/server/middlewares/validators/shared/videos.ts | |||
@@ -180,18 +180,16 @@ async function checkCanAccessVideoStaticFiles (options: { | |||
180 | return checkCanSeeVideo(options) | 180 | return checkCanSeeVideo(options) |
181 | } | 181 | } |
182 | 182 | ||
183 | if (!video.hasPrivateStaticPath()) return true | ||
184 | |||
185 | const videoFileToken = req.query.videoFileToken | 183 | const videoFileToken = req.query.videoFileToken |
186 | if (!videoFileToken) { | 184 | if (videoFileToken && VideoTokensManager.Instance.hasToken({ token: videoFileToken, videoUUID: video.uuid })) { |
187 | res.sendStatus(HttpStatusCode.FORBIDDEN_403) | 185 | const user = VideoTokensManager.Instance.getUserFromToken({ token: videoFileToken }) |
188 | return false | ||
189 | } | ||
190 | 186 | ||
191 | if (VideoTokensManager.Instance.hasToken({ token: videoFileToken, videoUUID: video.uuid })) { | 187 | res.locals.videoFileToken = { user } |
192 | return true | 188 | return true |
193 | } | 189 | } |
194 | 190 | ||
191 | if (!video.hasPrivateStaticPath()) return true | ||
192 | |||
195 | res.sendStatus(HttpStatusCode.FORBIDDEN_403) | 193 | res.sendStatus(HttpStatusCode.FORBIDDEN_403) |
196 | return false | 194 | return false |
197 | } | 195 | } |
diff --git a/server/tests/api/activitypub/cleaner.ts b/server/tests/api/activitypub/cleaner.ts index eb6779123..1c1495022 100644 --- a/server/tests/api/activitypub/cleaner.ts +++ b/server/tests/api/activitypub/cleaner.ts | |||
@@ -148,7 +148,7 @@ describe('Test AP cleaner', function () { | |||
148 | it('Should destroy server 3 internal shares and correctly clean them', async function () { | 148 | it('Should destroy server 3 internal shares and correctly clean them', async function () { |
149 | this.timeout(20000) | 149 | this.timeout(20000) |
150 | 150 | ||
151 | const preCount = await servers[0].sql.getCount('videoShare') | 151 | const preCount = await servers[0].sql.getVideoShareCount() |
152 | expect(preCount).to.equal(6) | 152 | expect(preCount).to.equal(6) |
153 | 153 | ||
154 | await servers[2].sql.deleteAll('videoShare') | 154 | await servers[2].sql.deleteAll('videoShare') |
@@ -156,7 +156,7 @@ describe('Test AP cleaner', function () { | |||
156 | await waitJobs(servers) | 156 | await waitJobs(servers) |
157 | 157 | ||
158 | // Still 6 because we don't have remote shares on local videos | 158 | // Still 6 because we don't have remote shares on local videos |
159 | const postCount = await servers[0].sql.getCount('videoShare') | 159 | const postCount = await servers[0].sql.getVideoShareCount() |
160 | expect(postCount).to.equal(6) | 160 | expect(postCount).to.equal(6) |
161 | }) | 161 | }) |
162 | 162 | ||
@@ -185,7 +185,7 @@ describe('Test AP cleaner', function () { | |||
185 | async function check (like: string, ofServerUrl: string, urlSuffix: string, remote: 'true' | 'false') { | 185 | async function check (like: string, ofServerUrl: string, urlSuffix: string, remote: 'true' | 'false') { |
186 | const query = `SELECT "videoId", "accountVideoRate".url FROM "accountVideoRate" ` + | 186 | const query = `SELECT "videoId", "accountVideoRate".url FROM "accountVideoRate" ` + |
187 | `INNER JOIN video ON "accountVideoRate"."videoId" = video.id AND remote IS ${remote} WHERE "accountVideoRate"."url" LIKE '${like}'` | 187 | `INNER JOIN video ON "accountVideoRate"."videoId" = video.id AND remote IS ${remote} WHERE "accountVideoRate"."url" LIKE '${like}'` |
188 | const res = await servers[0].sql.selectQuery(query) | 188 | const res = await servers[0].sql.selectQuery<{ url: string }>(query) |
189 | 189 | ||
190 | for (const rate of res) { | 190 | for (const rate of res) { |
191 | const matcher = new RegExp(`^${ofServerUrl}/accounts/root/dislikes/\\d+${urlSuffix}$`) | 191 | const matcher = new RegExp(`^${ofServerUrl}/accounts/root/dislikes/\\d+${urlSuffix}$`) |
@@ -231,7 +231,7 @@ describe('Test AP cleaner', function () { | |||
231 | const query = `SELECT "videoId", "videoComment".url, uuid as "videoUUID" FROM "videoComment" ` + | 231 | const query = `SELECT "videoId", "videoComment".url, uuid as "videoUUID" FROM "videoComment" ` + |
232 | `INNER JOIN video ON "videoComment"."videoId" = video.id AND remote IS ${remote} WHERE "videoComment"."url" LIKE '${like}'` | 232 | `INNER JOIN video ON "videoComment"."videoId" = video.id AND remote IS ${remote} WHERE "videoComment"."url" LIKE '${like}'` |
233 | 233 | ||
234 | const res = await servers[0].sql.selectQuery(query) | 234 | const res = await servers[0].sql.selectQuery<{ url: string, videoUUID: string }>(query) |
235 | 235 | ||
236 | for (const comment of res) { | 236 | for (const comment of res) { |
237 | const matcher = new RegExp(`${ofServerUrl}/videos/watch/${comment.videoUUID}/comments/\\d+${urlSuffix}`) | 237 | const matcher = new RegExp(`${ofServerUrl}/videos/watch/${comment.videoUUID}/comments/\\d+${urlSuffix}`) |
diff --git a/server/tests/api/check-params/redundancy.ts b/server/tests/api/check-params/redundancy.ts index 908407b9a..73dfd489d 100644 --- a/server/tests/api/check-params/redundancy.ts +++ b/server/tests/api/check-params/redundancy.ts | |||
@@ -24,7 +24,7 @@ describe('Test server redundancy API validators', function () { | |||
24 | // --------------------------------------------------------------- | 24 | // --------------------------------------------------------------- |
25 | 25 | ||
26 | before(async function () { | 26 | before(async function () { |
27 | this.timeout(80000) | 27 | this.timeout(160000) |
28 | 28 | ||
29 | servers = await createMultipleServers(2) | 29 | servers = await createMultipleServers(2) |
30 | 30 | ||
diff --git a/server/tests/api/live/live-fast-restream.ts b/server/tests/api/live/live-fast-restream.ts index c0bb8d529..f6959b83c 100644 --- a/server/tests/api/live/live-fast-restream.ts +++ b/server/tests/api/live/live-fast-restream.ts | |||
@@ -78,9 +78,15 @@ describe('Fast restream in live', function () { | |||
78 | const video = await server.videos.get({ id: liveId }) | 78 | const video = await server.videos.get({ id: liveId }) |
79 | expect(video.streamingPlaylists).to.have.lengthOf(1) | 79 | expect(video.streamingPlaylists).to.have.lengthOf(1) |
80 | 80 | ||
81 | await server.live.getSegmentFile({ videoUUID: liveId, segment: 0, playlistNumber: 0 }) | 81 | try { |
82 | await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) | 82 | await server.live.getSegmentFile({ videoUUID: liveId, segment: 0, playlistNumber: 0 }) |
83 | await makeRawRequest({ url: video.streamingPlaylists[0].segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) | 83 | await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) |
84 | await makeRawRequest({ url: video.streamingPlaylists[0].segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) | ||
85 | } catch (err) { | ||
86 | // FIXME: try to debug error in CI "Unexpected end of JSON input" | ||
87 | console.error(err) | ||
88 | throw err | ||
89 | } | ||
84 | 90 | ||
85 | await wait(100) | 91 | await wait(100) |
86 | } | 92 | } |
@@ -129,7 +135,7 @@ describe('Fast restream in live', function () { | |||
129 | await server.config.enableLive({ allowReplay: true, transcoding: true, resolutions: 'min' }) | 135 | await server.config.enableLive({ allowReplay: true, transcoding: true, resolutions: 'min' }) |
130 | }) | 136 | }) |
131 | 137 | ||
132 | it('Should correctly fast reastream in a permanent live with and without save replay', async function () { | 138 | it('Should correctly fast restream in a permanent live with and without save replay', async function () { |
133 | this.timeout(480000) | 139 | this.timeout(480000) |
134 | 140 | ||
135 | // A test can take a long time, so prefer to run them in parallel | 141 | // A test can take a long time, so prefer to run them in parallel |
diff --git a/server/tests/api/notifications/moderation-notifications.ts b/server/tests/api/notifications/moderation-notifications.ts index b127a7a31..c7b9b5fb0 100644 --- a/server/tests/api/notifications/moderation-notifications.ts +++ b/server/tests/api/notifications/moderation-notifications.ts | |||
@@ -34,7 +34,7 @@ describe('Test moderation notifications', function () { | |||
34 | let emails: object[] = [] | 34 | let emails: object[] = [] |
35 | 35 | ||
36 | before(async function () { | 36 | before(async function () { |
37 | this.timeout(120000) | 37 | this.timeout(50000) |
38 | 38 | ||
39 | const res = await prepareNotificationsTest(3) | 39 | const res = await prepareNotificationsTest(3) |
40 | emails = res.emails | 40 | emails = res.emails |
@@ -60,7 +60,7 @@ describe('Test moderation notifications', function () { | |||
60 | }) | 60 | }) |
61 | 61 | ||
62 | it('Should not send a notification to moderators on local abuse reported by an admin', async function () { | 62 | it('Should not send a notification to moderators on local abuse reported by an admin', async function () { |
63 | this.timeout(20000) | 63 | this.timeout(50000) |
64 | 64 | ||
65 | const name = 'video for abuse ' + buildUUID() | 65 | const name = 'video for abuse ' + buildUUID() |
66 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) | 66 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
@@ -72,7 +72,7 @@ describe('Test moderation notifications', function () { | |||
72 | }) | 72 | }) |
73 | 73 | ||
74 | it('Should send a notification to moderators on local video abuse', async function () { | 74 | it('Should send a notification to moderators on local video abuse', async function () { |
75 | this.timeout(20000) | 75 | this.timeout(50000) |
76 | 76 | ||
77 | const name = 'video for abuse ' + buildUUID() | 77 | const name = 'video for abuse ' + buildUUID() |
78 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) | 78 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
@@ -84,7 +84,7 @@ describe('Test moderation notifications', function () { | |||
84 | }) | 84 | }) |
85 | 85 | ||
86 | it('Should send a notification to moderators on remote video abuse', async function () { | 86 | it('Should send a notification to moderators on remote video abuse', async function () { |
87 | this.timeout(20000) | 87 | this.timeout(50000) |
88 | 88 | ||
89 | const name = 'video for abuse ' + buildUUID() | 89 | const name = 'video for abuse ' + buildUUID() |
90 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) | 90 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
@@ -99,7 +99,7 @@ describe('Test moderation notifications', function () { | |||
99 | }) | 99 | }) |
100 | 100 | ||
101 | it('Should send a notification to moderators on local comment abuse', async function () { | 101 | it('Should send a notification to moderators on local comment abuse', async function () { |
102 | this.timeout(20000) | 102 | this.timeout(50000) |
103 | 103 | ||
104 | const name = 'video for abuse ' + buildUUID() | 104 | const name = 'video for abuse ' + buildUUID() |
105 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) | 105 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
@@ -118,7 +118,7 @@ describe('Test moderation notifications', function () { | |||
118 | }) | 118 | }) |
119 | 119 | ||
120 | it('Should send a notification to moderators on remote comment abuse', async function () { | 120 | it('Should send a notification to moderators on remote comment abuse', async function () { |
121 | this.timeout(20000) | 121 | this.timeout(50000) |
122 | 122 | ||
123 | const name = 'video for abuse ' + buildUUID() | 123 | const name = 'video for abuse ' + buildUUID() |
124 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) | 124 | const video = await servers[0].videos.upload({ token: userToken1, attributes: { name } }) |
@@ -140,7 +140,7 @@ describe('Test moderation notifications', function () { | |||
140 | }) | 140 | }) |
141 | 141 | ||
142 | it('Should send a notification to moderators on local account abuse', async function () { | 142 | it('Should send a notification to moderators on local account abuse', async function () { |
143 | this.timeout(20000) | 143 | this.timeout(50000) |
144 | 144 | ||
145 | const username = 'user' + new Date().getTime() | 145 | const username = 'user' + new Date().getTime() |
146 | const { account } = await servers[0].users.create({ username, password: 'donald' }) | 146 | const { account } = await servers[0].users.create({ username, password: 'donald' }) |
@@ -153,7 +153,7 @@ describe('Test moderation notifications', function () { | |||
153 | }) | 153 | }) |
154 | 154 | ||
155 | it('Should send a notification to moderators on remote account abuse', async function () { | 155 | it('Should send a notification to moderators on remote account abuse', async function () { |
156 | this.timeout(20000) | 156 | this.timeout(50000) |
157 | 157 | ||
158 | const username = 'user' + new Date().getTime() | 158 | const username = 'user' + new Date().getTime() |
159 | const tmpToken = await servers[0].users.generateUserAndToken(username) | 159 | const tmpToken = await servers[0].users.generateUserAndToken(username) |
@@ -512,10 +512,14 @@ describe('Test moderation notifications', function () { | |||
512 | }) | 512 | }) |
513 | 513 | ||
514 | it('Should not send video publish notification if auto-blacklisted', async function () { | 514 | it('Should not send video publish notification if auto-blacklisted', async function () { |
515 | this.timeout(120000) | ||
516 | |||
515 | await checkVideoIsPublished({ ...userBaseParams, videoName, shortUUID, checkType: 'absence' }) | 517 | await checkVideoIsPublished({ ...userBaseParams, videoName, shortUUID, checkType: 'absence' }) |
516 | }) | 518 | }) |
517 | 519 | ||
518 | it('Should not send a local user subscription notification if auto-blacklisted', async function () { | 520 | it('Should not send a local user subscription notification if auto-blacklisted', async function () { |
521 | this.timeout(120000) | ||
522 | |||
519 | await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName, shortUUID, checkType: 'absence' }) | 523 | await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName, shortUUID, checkType: 'absence' }) |
520 | }) | 524 | }) |
521 | 525 | ||
@@ -524,7 +528,7 @@ describe('Test moderation notifications', function () { | |||
524 | }) | 528 | }) |
525 | 529 | ||
526 | it('Should send video published and unblacklist after video unblacklisted', async function () { | 530 | it('Should send video published and unblacklist after video unblacklisted', async function () { |
527 | this.timeout(40000) | 531 | this.timeout(120000) |
528 | 532 | ||
529 | await servers[0].blacklist.remove({ videoId: uuid }) | 533 | await servers[0].blacklist.remove({ videoId: uuid }) |
530 | 534 | ||
@@ -537,10 +541,14 @@ describe('Test moderation notifications', function () { | |||
537 | }) | 541 | }) |
538 | 542 | ||
539 | it('Should send a local user subscription notification after removed from blacklist', async function () { | 543 | it('Should send a local user subscription notification after removed from blacklist', async function () { |
544 | this.timeout(120000) | ||
545 | |||
540 | await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName, shortUUID, checkType: 'presence' }) | 546 | await checkNewVideoFromSubscription({ ...adminBaseParamsServer1, videoName, shortUUID, checkType: 'presence' }) |
541 | }) | 547 | }) |
542 | 548 | ||
543 | it('Should send a remote user subscription notification after removed from blacklist', async function () { | 549 | it('Should send a remote user subscription notification after removed from blacklist', async function () { |
550 | this.timeout(120000) | ||
551 | |||
544 | await checkNewVideoFromSubscription({ ...adminBaseParamsServer2, videoName, shortUUID, checkType: 'presence' }) | 552 | await checkNewVideoFromSubscription({ ...adminBaseParamsServer2, videoName, shortUUID, checkType: 'presence' }) |
545 | }) | 553 | }) |
546 | 554 | ||
@@ -576,7 +584,7 @@ describe('Test moderation notifications', function () { | |||
576 | }) | 584 | }) |
577 | 585 | ||
578 | it('Should not send publish/subscription notifications after scheduled update if video still auto-blacklisted', async function () { | 586 | it('Should not send publish/subscription notifications after scheduled update if video still auto-blacklisted', async function () { |
579 | this.timeout(40000) | 587 | this.timeout(120000) |
580 | 588 | ||
581 | // In 2 seconds | 589 | // In 2 seconds |
582 | const updateAt = new Date(new Date().getTime() + 2000) | 590 | const updateAt = new Date(new Date().getTime() + 2000) |
diff --git a/server/tests/api/object-storage/video-static-file-privacy.ts b/server/tests/api/object-storage/video-static-file-privacy.ts index 71ad35a43..869d437d5 100644 --- a/server/tests/api/object-storage/video-static-file-privacy.ts +++ b/server/tests/api/object-storage/video-static-file-privacy.ts | |||
@@ -120,7 +120,7 @@ describe('Object storage for video static file privacy', function () { | |||
120 | // --------------------------------------------------------------------------- | 120 | // --------------------------------------------------------------------------- |
121 | 121 | ||
122 | it('Should upload a private video and have appropriate object storage ACL', async function () { | 122 | it('Should upload a private video and have appropriate object storage ACL', async function () { |
123 | this.timeout(60000) | 123 | this.timeout(120000) |
124 | 124 | ||
125 | { | 125 | { |
126 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) | 126 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.PRIVATE }) |
@@ -138,7 +138,7 @@ describe('Object storage for video static file privacy', function () { | |||
138 | }) | 138 | }) |
139 | 139 | ||
140 | it('Should upload a public video and have appropriate object storage ACL', async function () { | 140 | it('Should upload a public video and have appropriate object storage ACL', async function () { |
141 | this.timeout(60000) | 141 | this.timeout(120000) |
142 | 142 | ||
143 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.UNLISTED }) | 143 | const { uuid } = await server.videos.quickUpload({ name: 'video', privacy: VideoPrivacy.UNLISTED }) |
144 | await waitJobs([ server ]) | 144 | await waitJobs([ server ]) |
diff --git a/server/tests/api/videos/video-channel-syncs.ts b/server/tests/api/videos/video-channel-syncs.ts index 91291524d..dd483f95e 100644 --- a/server/tests/api/videos/video-channel-syncs.ts +++ b/server/tests/api/videos/video-channel-syncs.ts | |||
@@ -307,6 +307,7 @@ describe('Test channel synchronizations', function () { | |||
307 | }) | 307 | }) |
308 | } | 308 | } |
309 | 309 | ||
310 | runSuite('youtube-dl') | 310 | // FIXME: suite is broken with youtube-dl |
311 | // runSuite('youtube-dl') | ||
311 | runSuite('yt-dlp') | 312 | runSuite('yt-dlp') |
312 | }) | 313 | }) |
diff --git a/server/tests/feeds/feeds.ts b/server/tests/feeds/feeds.ts index 906dab1a3..7345f728a 100644 --- a/server/tests/feeds/feeds.ts +++ b/server/tests/feeds/feeds.ts | |||
@@ -189,7 +189,7 @@ describe('Test syndication feeds', () => { | |||
189 | const jsonObj = JSON.parse(json) | 189 | const jsonObj = JSON.parse(json) |
190 | expect(jsonObj.items.length).to.be.equal(1) | 190 | expect(jsonObj.items.length).to.be.equal(1) |
191 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | 191 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
192 | expect(jsonObj.items[0].author.name).to.equal('root') | 192 | expect(jsonObj.items[0].author.name).to.equal('Main root channel') |
193 | } | 193 | } |
194 | 194 | ||
195 | { | 195 | { |
@@ -197,7 +197,7 @@ describe('Test syndication feeds', () => { | |||
197 | const jsonObj = JSON.parse(json) | 197 | const jsonObj = JSON.parse(json) |
198 | expect(jsonObj.items.length).to.be.equal(1) | 198 | expect(jsonObj.items.length).to.be.equal(1) |
199 | expect(jsonObj.items[0].title).to.equal('user video') | 199 | expect(jsonObj.items[0].title).to.equal('user video') |
200 | expect(jsonObj.items[0].author.name).to.equal('john') | 200 | expect(jsonObj.items[0].author.name).to.equal('Main john channel') |
201 | } | 201 | } |
202 | 202 | ||
203 | for (const server of servers) { | 203 | for (const server of servers) { |
@@ -223,7 +223,7 @@ describe('Test syndication feeds', () => { | |||
223 | const jsonObj = JSON.parse(json) | 223 | const jsonObj = JSON.parse(json) |
224 | expect(jsonObj.items.length).to.be.equal(1) | 224 | expect(jsonObj.items.length).to.be.equal(1) |
225 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') | 225 | expect(jsonObj.items[0].title).to.equal('my super name for server 1') |
226 | expect(jsonObj.items[0].author.name).to.equal('root') | 226 | expect(jsonObj.items[0].author.name).to.equal('Main root channel') |
227 | } | 227 | } |
228 | 228 | ||
229 | { | 229 | { |
@@ -231,7 +231,7 @@ describe('Test syndication feeds', () => { | |||
231 | const jsonObj = JSON.parse(json) | 231 | const jsonObj = JSON.parse(json) |
232 | expect(jsonObj.items.length).to.be.equal(1) | 232 | expect(jsonObj.items.length).to.be.equal(1) |
233 | expect(jsonObj.items[0].title).to.equal('user video') | 233 | expect(jsonObj.items[0].title).to.equal('user video') |
234 | expect(jsonObj.items[0].author.name).to.equal('john') | 234 | expect(jsonObj.items[0].author.name).to.equal('Main john channel') |
235 | } | 235 | } |
236 | 236 | ||
237 | for (const server of servers) { | 237 | for (const server of servers) { |
diff --git a/server/tests/fixtures/peertube-plugin-test-four/main.js b/server/tests/fixtures/peertube-plugin-test-four/main.js index 3e848c49e..b10177b45 100644 --- a/server/tests/fixtures/peertube-plugin-test-four/main.js +++ b/server/tests/fixtures/peertube-plugin-test-four/main.js | |||
@@ -76,6 +76,12 @@ async function register ({ | |||
76 | return res.json({ serverConfig }) | 76 | return res.json({ serverConfig }) |
77 | }) | 77 | }) |
78 | 78 | ||
79 | router.get('/server-listening-config', async (req, res) => { | ||
80 | const config = await peertubeHelpers.config.getServerListeningConfig() | ||
81 | |||
82 | return res.json({ config }) | ||
83 | }) | ||
84 | |||
79 | router.get('/static-route', async (req, res) => { | 85 | router.get('/static-route', async (req, res) => { |
80 | const staticRoute = peertubeHelpers.plugin.getBaseStaticRoute() | 86 | const staticRoute = peertubeHelpers.plugin.getBaseStaticRoute() |
81 | 87 | ||
diff --git a/server/tests/fixtures/peertube-plugin-test/main.js b/server/tests/fixtures/peertube-plugin-test/main.js index 19dccf26e..19ba9f278 100644 --- a/server/tests/fixtures/peertube-plugin-test/main.js +++ b/server/tests/fixtures/peertube-plugin-test/main.js | |||
@@ -250,7 +250,10 @@ async function register ({ registerHook, registerSetting, settingsManager, stora | |||
250 | 250 | ||
251 | registerHook({ | 251 | registerHook({ |
252 | target: 'filter:api.download.video.allowed.result', | 252 | target: 'filter:api.download.video.allowed.result', |
253 | handler: (result, params) => { | 253 | handler: async (result, params) => { |
254 | const loggedInUser = await peertubeHelpers.user.getAuthUser(params.res) | ||
255 | if (loggedInUser) return { allowed: true } | ||
256 | |||
254 | if (params && !params.streamingPlaylist && params.video.name.includes('bad file')) { | 257 | if (params && !params.streamingPlaylist && params.video.name.includes('bad file')) { |
255 | return { allowed: false, errorMessage: 'Cao Cao' } | 258 | return { allowed: false, errorMessage: 'Cao Cao' } |
256 | } | 259 | } |
diff --git a/server/tests/plugins/filter-hooks.ts b/server/tests/plugins/filter-hooks.ts index 083fd43ca..6724b3bf8 100644 --- a/server/tests/plugins/filter-hooks.ts +++ b/server/tests/plugins/filter-hooks.ts | |||
@@ -430,6 +430,7 @@ describe('Test plugin filter hooks', function () { | |||
430 | 430 | ||
431 | describe('Download hooks', function () { | 431 | describe('Download hooks', function () { |
432 | const downloadVideos: VideoDetails[] = [] | 432 | const downloadVideos: VideoDetails[] = [] |
433 | let downloadVideo2Token: string | ||
433 | 434 | ||
434 | before(async function () { | 435 | before(async function () { |
435 | this.timeout(120000) | 436 | this.timeout(120000) |
@@ -459,6 +460,8 @@ describe('Test plugin filter hooks', function () { | |||
459 | for (const uuid of uuids) { | 460 | for (const uuid of uuids) { |
460 | downloadVideos.push(await servers[0].videos.get({ id: uuid })) | 461 | downloadVideos.push(await servers[0].videos.get({ id: uuid })) |
461 | } | 462 | } |
463 | |||
464 | downloadVideo2Token = await servers[0].videoToken.getVideoFileToken({ videoId: downloadVideos[2].uuid }) | ||
462 | }) | 465 | }) |
463 | 466 | ||
464 | it('Should run filter:api.download.torrent.allowed.result', async function () { | 467 | it('Should run filter:api.download.torrent.allowed.result', async function () { |
@@ -471,32 +474,42 @@ describe('Test plugin filter hooks', function () { | |||
471 | 474 | ||
472 | it('Should run filter:api.download.video.allowed.result', async function () { | 475 | it('Should run filter:api.download.video.allowed.result', async function () { |
473 | { | 476 | { |
474 | const res = await makeRawRequest({ url: downloadVideos[1].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | 477 | const refused = downloadVideos[1].files[0].fileDownloadUrl |
478 | const allowed = [ | ||
479 | downloadVideos[0].files[0].fileDownloadUrl, | ||
480 | downloadVideos[2].files[0].fileDownloadUrl | ||
481 | ] | ||
482 | |||
483 | const res = await makeRawRequest({ url: refused, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
475 | expect(res.body.error).to.equal('Cao Cao') | 484 | expect(res.body.error).to.equal('Cao Cao') |
476 | 485 | ||
477 | await makeRawRequest({ url: downloadVideos[0].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) | 486 | for (const url of allowed) { |
478 | await makeRawRequest({ url: downloadVideos[2].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) | 487 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) |
488 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) | ||
489 | } | ||
479 | } | 490 | } |
480 | 491 | ||
481 | { | 492 | { |
482 | const res = await makeRawRequest({ | 493 | const refused = downloadVideos[2].streamingPlaylists[0].files[0].fileDownloadUrl |
483 | url: downloadVideos[2].streamingPlaylists[0].files[0].fileDownloadUrl, | ||
484 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
485 | }) | ||
486 | 494 | ||
487 | expect(res.body.error).to.equal('Sun Jian') | 495 | const allowed = [ |
496 | downloadVideos[2].files[0].fileDownloadUrl, | ||
497 | downloadVideos[0].streamingPlaylists[0].files[0].fileDownloadUrl, | ||
498 | downloadVideos[1].streamingPlaylists[0].files[0].fileDownloadUrl | ||
499 | ] | ||
488 | 500 | ||
489 | await makeRawRequest({ url: downloadVideos[2].files[0].fileDownloadUrl, expectedStatus: HttpStatusCode.OK_200 }) | 501 | // Only streaming playlist is refuse |
502 | const res = await makeRawRequest({ url: refused, expectedStatus: HttpStatusCode.FORBIDDEN_403 }) | ||
503 | expect(res.body.error).to.equal('Sun Jian') | ||
490 | 504 | ||
491 | await makeRawRequest({ | 505 | // But not we there is a user in res |
492 | url: downloadVideos[0].streamingPlaylists[0].files[0].fileDownloadUrl, | 506 | await makeRawRequest({ url: refused, token: servers[0].accessToken, expectedStatus: HttpStatusCode.OK_200 }) |
493 | expectedStatus: HttpStatusCode.OK_200 | 507 | await makeRawRequest({ url: refused, query: { videoFileToken: downloadVideo2Token }, expectedStatus: HttpStatusCode.OK_200 }) |
494 | }) | ||
495 | 508 | ||
496 | await makeRawRequest({ | 509 | // Other files work |
497 | url: downloadVideos[1].streamingPlaylists[0].files[0].fileDownloadUrl, | 510 | for (const url of allowed) { |
498 | expectedStatus: HttpStatusCode.OK_200 | 511 | await makeRawRequest({ url, expectedStatus: HttpStatusCode.OK_200 }) |
499 | }) | 512 | } |
500 | } | 513 | } |
501 | }) | 514 | }) |
502 | }) | 515 | }) |
diff --git a/server/tests/plugins/plugin-helpers.ts b/server/tests/plugins/plugin-helpers.ts index 038e3f0d6..e25992723 100644 --- a/server/tests/plugins/plugin-helpers.ts +++ b/server/tests/plugins/plugin-helpers.ts | |||
@@ -64,6 +64,18 @@ describe('Test plugin helpers', function () { | |||
64 | await servers[0].servers.waitUntilLog(`server url is ${servers[0].url}`) | 64 | await servers[0].servers.waitUntilLog(`server url is ${servers[0].url}`) |
65 | }) | 65 | }) |
66 | 66 | ||
67 | it('Should have the correct listening config', async function () { | ||
68 | const res = await makeGetRequest({ | ||
69 | url: servers[0].url, | ||
70 | path: '/plugins/test-four/router/server-listening-config', | ||
71 | expectedStatus: HttpStatusCode.OK_200 | ||
72 | }) | ||
73 | |||
74 | expect(res.body.config).to.exist | ||
75 | expect(res.body.config.hostname).to.equal('::') | ||
76 | expect(res.body.config.port).to.equal(servers[0].port) | ||
77 | }) | ||
78 | |||
67 | it('Should have the correct config', async function () { | 79 | it('Should have the correct config', async function () { |
68 | const res = await makeGetRequest({ | 80 | const res = await makeGetRequest({ |
69 | url: servers[0].url, | 81 | url: servers[0].url, |
diff --git a/server/types/express.d.ts b/server/types/express.d.ts index 3738ffc47..99244d2a0 100644 --- a/server/types/express.d.ts +++ b/server/types/express.d.ts | |||
@@ -10,6 +10,7 @@ import { | |||
10 | MChannelBannerAccountDefault, | 10 | MChannelBannerAccountDefault, |
11 | MChannelSyncChannel, | 11 | MChannelSyncChannel, |
12 | MStreamingPlaylist, | 12 | MStreamingPlaylist, |
13 | MUserAccountUrl, | ||
13 | MVideoChangeOwnershipFull, | 14 | MVideoChangeOwnershipFull, |
14 | MVideoFile, | 15 | MVideoFile, |
15 | MVideoFormattableDetails, | 16 | MVideoFormattableDetails, |
@@ -187,6 +188,10 @@ declare module 'express' { | |||
187 | actor: MActorAccountChannelId | 188 | actor: MActorAccountChannelId |
188 | } | 189 | } |
189 | 190 | ||
191 | videoFileToken?: { | ||
192 | user: MUserAccountUrl | ||
193 | } | ||
194 | |||
190 | authenticated?: boolean | 195 | authenticated?: boolean |
191 | 196 | ||
192 | registeredPlugin?: RegisteredPlugin | 197 | registeredPlugin?: RegisteredPlugin |
diff --git a/server/types/plugins/register-server-option.model.ts b/server/types/plugins/register-server-option.model.ts index 1e2bd830e..df419fff4 100644 --- a/server/types/plugins/register-server-option.model.ts +++ b/server/types/plugins/register-server-option.model.ts | |||
@@ -71,6 +71,9 @@ export type PeerTubeHelpers = { | |||
71 | config: { | 71 | config: { |
72 | getWebserverUrl: () => string | 72 | getWebserverUrl: () => string |
73 | 73 | ||
74 | // PeerTube >= 5.1 | ||
75 | getServerListeningConfig: () => { hostname: string, port: number } | ||
76 | |||
74 | getServerConfig: () => Promise<ServerConfig> | 77 | getServerConfig: () => Promise<ServerConfig> |
75 | } | 78 | } |
76 | 79 | ||