server: serve files from storage/well-known (#5214)
* server: serve files from storage/well-known closes #5206 * well-known: add tests * test: try to skip new tests * test: another try * fix(config/prod): well_known path * test: fix broken tests * Update misc-endpoints.ts * Use getDirectoryPath for tests * Fix tests Co-authored-by: Chocobozzz <me@florianbigard.com>
This commit is contained in:
parent
cfd57d2ca0
commit
6c5f0d3aeb
|
@ -122,6 +122,7 @@ storage:
|
||||||
captions: 'storage/captions/'
|
captions: 'storage/captions/'
|
||||||
cache: 'storage/cache/'
|
cache: 'storage/cache/'
|
||||||
plugins: 'storage/plugins/'
|
plugins: 'storage/plugins/'
|
||||||
|
well_known: 'storage/well-known/'
|
||||||
# Overridable client files in client/dist/assets/images:
|
# Overridable client files in client/dist/assets/images:
|
||||||
# - logo.svg
|
# - logo.svg
|
||||||
# - favicon.png
|
# - favicon.png
|
||||||
|
|
|
@ -120,6 +120,7 @@ storage:
|
||||||
captions: '/var/www/peertube/storage/captions/'
|
captions: '/var/www/peertube/storage/captions/'
|
||||||
cache: '/var/www/peertube/storage/cache/'
|
cache: '/var/www/peertube/storage/cache/'
|
||||||
plugins: '/var/www/peertube/storage/plugins/'
|
plugins: '/var/www/peertube/storage/plugins/'
|
||||||
|
well_known: '/var/www/peertube/storage/well-known/'
|
||||||
# Overridable client files in client/dist/assets/images:
|
# Overridable client files in client/dist/assets/images:
|
||||||
# - logo.svg
|
# - logo.svg
|
||||||
# - favicon.png
|
# - favicon.png
|
||||||
|
|
|
@ -23,6 +23,7 @@ storage:
|
||||||
captions: 'test1/captions/'
|
captions: 'test1/captions/'
|
||||||
cache: 'test1/cache/'
|
cache: 'test1/cache/'
|
||||||
plugins: 'test1/plugins/'
|
plugins: 'test1/plugins/'
|
||||||
|
well_known: 'test1/well-known/'
|
||||||
client_overrides: 'test1/client-overrides/'
|
client_overrides: 'test1/client-overrides/'
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
|
|
|
@ -23,6 +23,7 @@ storage:
|
||||||
captions: 'test2/captions/'
|
captions: 'test2/captions/'
|
||||||
cache: 'test2/cache/'
|
cache: 'test2/cache/'
|
||||||
plugins: 'test2/plugins/'
|
plugins: 'test2/plugins/'
|
||||||
|
well_known: 'test2/well-known/'
|
||||||
client_overrides: 'test2/client-overrides/'
|
client_overrides: 'test2/client-overrides/'
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
|
|
|
@ -23,6 +23,7 @@ storage:
|
||||||
captions: 'test3/captions/'
|
captions: 'test3/captions/'
|
||||||
cache: 'test3/cache/'
|
cache: 'test3/cache/'
|
||||||
plugins: 'test3/plugins/'
|
plugins: 'test3/plugins/'
|
||||||
|
well_known: 'test3/well-known/'
|
||||||
client_overrides: 'test3/client-overrides/'
|
client_overrides: 'test3/client-overrides/'
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
|
|
|
@ -23,6 +23,7 @@ storage:
|
||||||
captions: 'test4/captions/'
|
captions: 'test4/captions/'
|
||||||
cache: 'test4/cache/'
|
cache: 'test4/cache/'
|
||||||
plugins: 'test4/plugins/'
|
plugins: 'test4/plugins/'
|
||||||
|
well_known: 'test4/well-known/'
|
||||||
client_overrides: 'test4/client-overrides/'
|
client_overrides: 'test4/client-overrides/'
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
|
|
|
@ -23,6 +23,7 @@ storage:
|
||||||
captions: 'test5/captions/'
|
captions: 'test5/captions/'
|
||||||
cache: 'test5/cache/'
|
cache: 'test5/cache/'
|
||||||
plugins: 'test5/plugins/'
|
plugins: 'test5/plugins/'
|
||||||
|
well_known: 'test5/well-known/'
|
||||||
client_overrides: 'test5/client-overrides/'
|
client_overrides: 'test5/client-overrides/'
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
|
|
|
@ -23,6 +23,7 @@ storage:
|
||||||
captions: 'test6/captions/'
|
captions: 'test6/captions/'
|
||||||
cache: 'test6/cache/'
|
cache: 'test6/cache/'
|
||||||
plugins: 'test6/plugins/'
|
plugins: 'test6/plugins/'
|
||||||
|
well_known: 'test6/well-known/'
|
||||||
client_overrides: 'test6/client-overrides/'
|
client_overrides: 'test6/client-overrides/'
|
||||||
|
|
||||||
admin:
|
admin:
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { root } from '@shared/core-utils'
|
||||||
import { CONFIG } from '../initializers/config'
|
import { CONFIG } from '../initializers/config'
|
||||||
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
|
import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
|
||||||
import { cacheRoute } from '../middlewares/cache/cache'
|
import { cacheRoute } from '../middlewares/cache/cache'
|
||||||
|
import { handleStaticError } from '@server/middlewares'
|
||||||
|
|
||||||
const wellKnownRouter = express.Router()
|
const wellKnownRouter = express.Router()
|
||||||
|
|
||||||
|
@ -69,6 +70,12 @@ wellKnownRouter.use('/.well-known/host-meta',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
wellKnownRouter.use('/.well-known/',
|
||||||
|
cacheRoute(ROUTE_CACHE_LIFETIME.WELL_KNOWN),
|
||||||
|
express.static(CONFIG.STORAGE.WELL_KNOWN_DIR, { fallthrough: false }),
|
||||||
|
handleStaticError
|
||||||
|
)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -16,7 +16,7 @@ function checkMissedConfig () {
|
||||||
'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address',
|
'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address',
|
||||||
'email.body.signature', 'email.subject.prefix',
|
'email.body.signature', 'email.subject.prefix',
|
||||||
'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache',
|
'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache',
|
||||||
'storage.redundancy', 'storage.tmp', 'storage.streaming_playlists', 'storage.plugins',
|
'storage.redundancy', 'storage.tmp', 'storage.streaming_playlists', 'storage.plugins', 'storage.well_known',
|
||||||
'log.level',
|
'log.level',
|
||||||
'user.video_quota', 'user.video_quota_daily',
|
'user.video_quota', 'user.video_quota_daily',
|
||||||
'video_channels.max_per_user',
|
'video_channels.max_per_user',
|
||||||
|
|
|
@ -107,7 +107,8 @@ const CONFIG = {
|
||||||
TORRENTS_DIR: buildPath(config.get<string>('storage.torrents')),
|
TORRENTS_DIR: buildPath(config.get<string>('storage.torrents')),
|
||||||
CACHE_DIR: buildPath(config.get<string>('storage.cache')),
|
CACHE_DIR: buildPath(config.get<string>('storage.cache')),
|
||||||
PLUGINS_DIR: buildPath(config.get<string>('storage.plugins')),
|
PLUGINS_DIR: buildPath(config.get<string>('storage.plugins')),
|
||||||
CLIENT_OVERRIDES_DIR: buildPath(config.get<string>('storage.client_overrides'))
|
CLIENT_OVERRIDES_DIR: buildPath(config.get<string>('storage.client_overrides')),
|
||||||
|
WELL_KNOWN_DIR: buildPath(config.get<string>('storage.well_known'))
|
||||||
},
|
},
|
||||||
OBJECT_STORAGE: {
|
OBJECT_STORAGE: {
|
||||||
ENABLED: config.get<boolean>('object_storage.enabled'),
|
ENABLED: config.get<boolean>('object_storage.enabled'),
|
||||||
|
|
|
@ -116,7 +116,8 @@ const ROUTE_CACHE_LIFETIME = {
|
||||||
ACTIVITY_PUB: {
|
ACTIVITY_PUB: {
|
||||||
VIDEOS: '1 second' // 1 second, cache concurrent requests after a broadcast for example
|
VIDEOS: '1 second' // 1 second, cache concurrent requests after a broadcast for example
|
||||||
},
|
},
|
||||||
STATS: '4 hours'
|
STATS: '4 hours',
|
||||||
|
WELL_KNOWN: '1 day'
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -159,8 +159,8 @@ async function check2Webseeds (videoUUID?: string) {
|
||||||
const { webtorrentFilenames } = await ensureSameFilenames(videoUUID)
|
const { webtorrentFilenames } = await ensureSameFilenames(videoUUID)
|
||||||
|
|
||||||
const directories = [
|
const directories = [
|
||||||
'test' + servers[0].internalServerNumber + '/redundancy',
|
servers[0].getDirectoryPath('redundancy'),
|
||||||
'test' + servers[1].internalServerNumber + '/videos'
|
servers[1].getDirectoryPath('videos')
|
||||||
]
|
]
|
||||||
|
|
||||||
for (const directory of directories) {
|
for (const directory of directories) {
|
||||||
|
@ -214,8 +214,8 @@ async function check1PlaylistRedundancies (videoUUID?: string) {
|
||||||
const { hlsFilenames } = await ensureSameFilenames(videoUUID)
|
const { hlsFilenames } = await ensureSameFilenames(videoUUID)
|
||||||
|
|
||||||
const directories = [
|
const directories = [
|
||||||
'test' + servers[0].internalServerNumber + '/redundancy/hls',
|
servers[0].getDirectoryPath('redundancy/hls'),
|
||||||
'test' + servers[1].internalServerNumber + '/streaming-playlists/hls'
|
servers[1].getDirectoryPath('streaming-playlists/hls')
|
||||||
]
|
]
|
||||||
|
|
||||||
for (const directory of directories) {
|
for (const directory of directories) {
|
||||||
|
|
|
@ -197,7 +197,7 @@ describe('Test users with multiple servers', function () {
|
||||||
it('Should not have actor files', async () => {
|
it('Should not have actor files', async () => {
|
||||||
for (const server of servers) {
|
for (const server of servers) {
|
||||||
for (const userAvatarFilename of userAvatarFilenames) {
|
for (const userAvatarFilename of userAvatarFilenames) {
|
||||||
await checkActorFilesWereRemoved(userAvatarFilename, server.internalServerNumber)
|
await checkActorFilesWereRemoved(userAvatarFilename, server)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1049,7 +1049,7 @@ describe('Test video playlists', function () {
|
||||||
this.timeout(30000)
|
this.timeout(30000)
|
||||||
|
|
||||||
for (const server of servers) {
|
for (const server of servers) {
|
||||||
await checkPlaylistFilesWereRemoved(playlistServer1UUID, server.internalServerNumber)
|
await checkPlaylistFilesWereRemoved(playlistServer1UUID, server)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,18 +1,24 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
|
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
|
import { writeJson } from 'fs-extra'
|
||||||
|
import { join } from 'path'
|
||||||
import { HttpStatusCode, VideoPrivacy } from '@shared/models'
|
import { HttpStatusCode, VideoPrivacy } from '@shared/models'
|
||||||
|
import { cleanupTests, createSingleServer, makeGetRequest, PeerTubeServer, setAccessTokensToServers } from '@shared/server-commands'
|
||||||
import { expectLogDoesNotContain } from './shared'
|
import { expectLogDoesNotContain } from './shared'
|
||||||
|
|
||||||
describe('Test misc endpoints', function () {
|
describe('Test misc endpoints', function () {
|
||||||
let server: PeerTubeServer
|
let server: PeerTubeServer
|
||||||
|
let wellKnownPath: string
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
this.timeout(120000)
|
this.timeout(120000)
|
||||||
|
|
||||||
server = await createSingleServer(1)
|
server = await createSingleServer(1)
|
||||||
|
|
||||||
await setAccessTokensToServers([ server ])
|
await setAccessTokensToServers([ server ])
|
||||||
|
|
||||||
|
wellKnownPath = server.getDirectoryPath('well-known')
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Test a well known endpoints', function () {
|
describe('Test a well known endpoints', function () {
|
||||||
|
@ -93,6 +99,28 @@ describe('Test misc endpoints', function () {
|
||||||
expect(remoteInteract).to.exist
|
expect(remoteInteract).to.exist
|
||||||
expect(remoteInteract.template).to.equal(server.url + '/remote-interaction?uri={uri}')
|
expect(remoteInteract.template).to.equal(server.url + '/remote-interaction?uri={uri}')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should return 404 for non-existing files in /.well-known', async function () {
|
||||||
|
await makeGetRequest({
|
||||||
|
url: server.url,
|
||||||
|
path: '/.well-known/non-existing-file',
|
||||||
|
expectedStatus: HttpStatusCode.NOT_FOUND_404
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should return custom file from /.well-known', async function () {
|
||||||
|
const filename = 'existing-file.json'
|
||||||
|
|
||||||
|
await writeJson(join(wellKnownPath, filename), { iThink: 'therefore I am' })
|
||||||
|
|
||||||
|
const { body } = await makeGetRequest({
|
||||||
|
url: server.url,
|
||||||
|
path: '/.well-known/' + filename,
|
||||||
|
expectedStatus: HttpStatusCode.OK_200
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(body.iThink).to.equal('therefore I am')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('Test classic static endpoints', function () {
|
describe('Test classic static endpoints', function () {
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { pathExists, readdir } from 'fs-extra'
|
import { pathExists, readdir } from 'fs-extra'
|
||||||
import { join } from 'path'
|
|
||||||
import { root } from '@shared/core-utils'
|
|
||||||
import { Account, VideoChannel } from '@shared/models'
|
import { Account, VideoChannel } from '@shared/models'
|
||||||
import { PeerTubeServer } from '@shared/server-commands'
|
import { PeerTubeServer } from '@shared/server-commands'
|
||||||
|
|
||||||
|
@ -31,11 +29,9 @@ async function expectAccountFollows (options: {
|
||||||
return expectActorFollow({ ...options, data })
|
return expectActorFollow({ ...options, data })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkActorFilesWereRemoved (filename: string, serverNumber: number) {
|
async function checkActorFilesWereRemoved (filename: string, server: PeerTubeServer) {
|
||||||
const testDirectory = 'test' + serverNumber
|
|
||||||
|
|
||||||
for (const directory of [ 'avatars' ]) {
|
for (const directory of [ 'avatars' ]) {
|
||||||
const directoryPath = join(root(), testDirectory, directory)
|
const directoryPath = server.getDirectoryPath(directory)
|
||||||
|
|
||||||
const directoryExists = await pathExists(directoryPath)
|
const directoryExists = await pathExists(directoryPath)
|
||||||
expect(directoryExists).to.be.true
|
expect(directoryExists).to.be.true
|
||||||
|
|
|
@ -2,22 +2,18 @@
|
||||||
|
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { pathExists, readdir } from 'fs-extra'
|
import { pathExists, readdir } from 'fs-extra'
|
||||||
import { join } from 'path'
|
|
||||||
import { root } from '@shared/core-utils'
|
|
||||||
import { PeerTubeServer } from '@shared/server-commands'
|
import { PeerTubeServer } from '@shared/server-commands'
|
||||||
|
|
||||||
async function checkTmpIsEmpty (server: PeerTubeServer) {
|
async function checkTmpIsEmpty (server: PeerTubeServer) {
|
||||||
await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ])
|
await checkDirectoryIsEmpty(server, 'tmp', [ 'plugins-global.css', 'hls', 'resumable-uploads' ])
|
||||||
|
|
||||||
if (await pathExists(join('test' + server.internalServerNumber, 'tmp', 'hls'))) {
|
if (await pathExists(server.getDirectoryPath('tmp/hls'))) {
|
||||||
await checkDirectoryIsEmpty(server, 'tmp/hls')
|
await checkDirectoryIsEmpty(server, 'tmp/hls')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkDirectoryIsEmpty (server: PeerTubeServer, directory: string, exceptions: string[] = []) {
|
async function checkDirectoryIsEmpty (server: PeerTubeServer, directory: string, exceptions: string[] = []) {
|
||||||
const testDirectory = 'test' + server.internalServerNumber
|
const directoryPath = server.getDirectoryPath(directory)
|
||||||
|
|
||||||
const directoryPath = join(root(), testDirectory, directory)
|
|
||||||
|
|
||||||
const directoryExists = await pathExists(directoryPath)
|
const directoryExists = await pathExists(directoryPath)
|
||||||
expect(directoryExists).to.be.true
|
expect(directoryExists).to.be.true
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { readdir } from 'fs-extra'
|
import { readdir } from 'fs-extra'
|
||||||
import { join } from 'path'
|
import { PeerTubeServer } from '@shared/server-commands'
|
||||||
import { root } from '@shared/core-utils'
|
|
||||||
|
|
||||||
async function checkPlaylistFilesWereRemoved (
|
async function checkPlaylistFilesWereRemoved (
|
||||||
playlistUUID: string,
|
playlistUUID: string,
|
||||||
internalServerNumber: number,
|
server: PeerTubeServer,
|
||||||
directories = [ 'thumbnails' ]
|
directories = [ 'thumbnails' ]
|
||||||
) {
|
) {
|
||||||
const testDirectory = 'test' + internalServerNumber
|
|
||||||
|
|
||||||
for (const directory of directories) {
|
for (const directory of directories) {
|
||||||
const directoryPath = join(root(), testDirectory, directory)
|
const directoryPath = server.getDirectoryPath(directory)
|
||||||
|
|
||||||
const files = await readdir(directoryPath)
|
const files = await readdir(directoryPath)
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
|
|
|
@ -182,6 +182,12 @@ export class PeerTubeServer {
|
||||||
this.port = parseInt(parsed.port)
|
this.port = parseInt(parsed.port)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDirectoryPath (directoryName: string) {
|
||||||
|
const testDirectory = 'test' + this.internalServerNumber
|
||||||
|
|
||||||
|
return join(root(), testDirectory, directoryName)
|
||||||
|
}
|
||||||
|
|
||||||
async flushAndRun (configOverride?: Object, options: RunServerOptions = {}) {
|
async flushAndRun (configOverride?: Object, options: RunServerOptions = {}) {
|
||||||
await ServersCommand.flushTests(this.internalServerNumber)
|
await ServersCommand.flushTests(this.internalServerNumber)
|
||||||
|
|
||||||
|
@ -341,19 +347,20 @@ export class PeerTubeServer {
|
||||||
suffix: '_test' + this.internalServerNumber
|
suffix: '_test' + this.internalServerNumber
|
||||||
},
|
},
|
||||||
storage: {
|
storage: {
|
||||||
tmp: `test${this.internalServerNumber}/tmp/`,
|
tmp: this.getDirectoryPath('tmp') + '/',
|
||||||
bin: `test${this.internalServerNumber}/bin/`,
|
bin: this.getDirectoryPath('bin') + '/',
|
||||||
avatars: `test${this.internalServerNumber}/avatars/`,
|
avatars: this.getDirectoryPath('avatars') + '/',
|
||||||
videos: `test${this.internalServerNumber}/videos/`,
|
videos: this.getDirectoryPath('videos') + '/',
|
||||||
streaming_playlists: `test${this.internalServerNumber}/streaming-playlists/`,
|
streaming_playlists: this.getDirectoryPath('streaming-playlists') + '/',
|
||||||
redundancy: `test${this.internalServerNumber}/redundancy/`,
|
redundancy: this.getDirectoryPath('redundancy') + '/',
|
||||||
logs: `test${this.internalServerNumber}/logs/`,
|
logs: this.getDirectoryPath('logs') + '/',
|
||||||
previews: `test${this.internalServerNumber}/previews/`,
|
previews: this.getDirectoryPath('previews') + '/',
|
||||||
thumbnails: `test${this.internalServerNumber}/thumbnails/`,
|
thumbnails: this.getDirectoryPath('thumbnails') + '/',
|
||||||
torrents: `test${this.internalServerNumber}/torrents/`,
|
torrents: this.getDirectoryPath('torrents') + '/',
|
||||||
captions: `test${this.internalServerNumber}/captions/`,
|
captions: this.getDirectoryPath('captions') + '/',
|
||||||
cache: `test${this.internalServerNumber}/cache/`,
|
cache: this.getDirectoryPath('cache') + '/',
|
||||||
plugins: `test${this.internalServerNumber}/plugins/`
|
plugins: this.getDirectoryPath('plugins') + '/',
|
||||||
|
well_known: this.getDirectoryPath('well-known') + '/'
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
email: `admin${this.internalServerNumber}@example.com`
|
email: `admin${this.internalServerNumber}@example.com`
|
||||||
|
|
|
@ -56,6 +56,7 @@ storage:
|
||||||
captions: '../data/captions/'
|
captions: '../data/captions/'
|
||||||
cache: '../data/cache/'
|
cache: '../data/cache/'
|
||||||
plugins: '../data/plugins/'
|
plugins: '../data/plugins/'
|
||||||
|
well_known: '../data/well-known/'
|
||||||
# Overridable client files in client/dist/assets/images :
|
# Overridable client files in client/dist/assets/images :
|
||||||
# - logo.svg
|
# - logo.svg
|
||||||
# - favicon.png
|
# - favicon.png
|
||||||
|
|
Loading…
Reference in New Issue