diff options
Diffstat (limited to 'server/controllers/static.ts')
-rw-r--r-- | server/controllers/static.ts | 271 |
1 files changed, 3 insertions, 268 deletions
diff --git a/server/controllers/static.ts b/server/controllers/static.ts index 87bceba7a..7668ceb82 100644 --- a/server/controllers/static.ts +++ b/server/controllers/static.ts | |||
@@ -1,37 +1,13 @@ | |||
1 | import cors from 'cors' | 1 | import cors from 'cors' |
2 | import express from 'express' | 2 | import express from 'express' |
3 | import { join } from 'path' | 3 | import { CONFIG } from '../initializers/config' |
4 | import { serveIndexHTML } from '@server/lib/client-html' | 4 | import { HLS_STREAMING_PLAYLIST_DIRECTORY, STATIC_MAX_AGE, STATIC_PATHS } from '../initializers/constants' |
5 | import { ServerConfigManager } from '@server/lib/server-config-manager' | ||
6 | import { HttpStatusCode } from '@shared/models' | ||
7 | import { HttpNodeinfoDiasporaSoftwareNsSchema20 } from '../../shared/models/nodeinfo/nodeinfo.model' | ||
8 | import { root } from '@shared/core-utils' | ||
9 | import { CONFIG, isEmailEnabled } from '../initializers/config' | ||
10 | import { | ||
11 | CONSTRAINTS_FIELDS, | ||
12 | DEFAULT_THEME_NAME, | ||
13 | HLS_STREAMING_PLAYLIST_DIRECTORY, | ||
14 | PEERTUBE_VERSION, | ||
15 | ROUTE_CACHE_LIFETIME, | ||
16 | STATIC_MAX_AGE, | ||
17 | STATIC_PATHS, | ||
18 | WEBSERVER | ||
19 | } from '../initializers/constants' | ||
20 | import { getThemeOrDefault } from '../lib/plugins/theme-utils' | ||
21 | import { asyncMiddleware } from '../middlewares' | ||
22 | import { cacheRoute } from '../middlewares/cache/cache' | ||
23 | import { UserModel } from '../models/user/user' | ||
24 | import { VideoModel } from '../models/video/video' | ||
25 | import { VideoCommentModel } from '../models/video/video-comment' | ||
26 | 5 | ||
27 | const staticRouter = express.Router() | 6 | const staticRouter = express.Router() |
28 | 7 | ||
8 | // Cors is very important to let other servers access torrent and video files | ||
29 | staticRouter.use(cors()) | 9 | staticRouter.use(cors()) |
30 | 10 | ||
31 | /* | ||
32 | Cors is very important to let other servers access torrent and video files | ||
33 | */ | ||
34 | |||
35 | // Videos path for webseed | 11 | // Videos path for webseed |
36 | staticRouter.use( | 12 | staticRouter.use( |
37 | STATIC_PATHS.WEBSEED, | 13 | STATIC_PATHS.WEBSEED, |
@@ -45,7 +21,6 @@ staticRouter.use( | |||
45 | // HLS | 21 | // HLS |
46 | staticRouter.use( | 22 | staticRouter.use( |
47 | STATIC_PATHS.STREAMING_PLAYLISTS.HLS, | 23 | STATIC_PATHS.STREAMING_PLAYLISTS.HLS, |
48 | cors(), | ||
49 | express.static(HLS_STREAMING_PLAYLIST_DIRECTORY, { fallthrough: false }) // 404 if the file does not exist | 24 | express.static(HLS_STREAMING_PLAYLIST_DIRECTORY, { fallthrough: false }) // 404 if the file does not exist |
50 | ) | 25 | ) |
51 | 26 | ||
@@ -56,248 +31,8 @@ staticRouter.use( | |||
56 | express.static(thumbnailsPhysicalPath, { maxAge: STATIC_MAX_AGE.SERVER, fallthrough: false }) // 404 if the file does not exist | 31 | express.static(thumbnailsPhysicalPath, { maxAge: STATIC_MAX_AGE.SERVER, fallthrough: false }) // 404 if the file does not exist |
57 | ) | 32 | ) |
58 | 33 | ||
59 | // robots.txt service | ||
60 | staticRouter.get('/robots.txt', | ||
61 | cacheRoute(ROUTE_CACHE_LIFETIME.ROBOTS), | ||
62 | (_, res: express.Response) => { | ||
63 | res.type('text/plain') | ||
64 | |||
65 | return res.send(CONFIG.INSTANCE.ROBOTS) | ||
66 | } | ||
67 | ) | ||
68 | |||
69 | staticRouter.all('/teapot', | ||
70 | getCup, | ||
71 | asyncMiddleware(serveIndexHTML) | ||
72 | ) | ||
73 | |||
74 | // security.txt service | ||
75 | staticRouter.get('/security.txt', | ||
76 | (_, res: express.Response) => { | ||
77 | return res.redirect(HttpStatusCode.MOVED_PERMANENTLY_301, '/.well-known/security.txt') | ||
78 | } | ||
79 | ) | ||
80 | |||
81 | staticRouter.get('/.well-known/security.txt', | ||
82 | cacheRoute(ROUTE_CACHE_LIFETIME.SECURITYTXT), | ||
83 | (_, res: express.Response) => { | ||
84 | res.type('text/plain') | ||
85 | return res.send(CONFIG.INSTANCE.SECURITYTXT + CONFIG.INSTANCE.SECURITYTXT_CONTACT) | ||
86 | } | ||
87 | ) | ||
88 | |||
89 | // nodeinfo service | ||
90 | staticRouter.use('/.well-known/nodeinfo', | ||
91 | cacheRoute(ROUTE_CACHE_LIFETIME.NODEINFO), | ||
92 | (_, res: express.Response) => { | ||
93 | return res.json({ | ||
94 | links: [ | ||
95 | { | ||
96 | rel: 'http://nodeinfo.diaspora.software/ns/schema/2.0', | ||
97 | href: WEBSERVER.URL + '/nodeinfo/2.0.json' | ||
98 | } | ||
99 | ] | ||
100 | }) | ||
101 | } | ||
102 | ) | ||
103 | staticRouter.use('/nodeinfo/:version.json', | ||
104 | cacheRoute(ROUTE_CACHE_LIFETIME.NODEINFO), | ||
105 | asyncMiddleware(generateNodeinfo) | ||
106 | ) | ||
107 | |||
108 | // dnt-policy.txt service (see https://www.eff.org/dnt-policy) | ||
109 | staticRouter.use('/.well-known/dnt-policy.txt', | ||
110 | cacheRoute(ROUTE_CACHE_LIFETIME.DNT_POLICY), | ||
111 | (_, res: express.Response) => { | ||
112 | res.type('text/plain') | ||
113 | |||
114 | return res.sendFile(join(root(), 'dist/server/static/dnt-policy/dnt-policy-1.0.txt')) | ||
115 | } | ||
116 | ) | ||
117 | |||
118 | // dnt service (see https://www.w3.org/TR/tracking-dnt/#status-resource) | ||
119 | staticRouter.use('/.well-known/dnt/', | ||
120 | (_, res: express.Response) => { | ||
121 | res.json({ tracking: 'N' }) | ||
122 | } | ||
123 | ) | ||
124 | |||
125 | staticRouter.use('/.well-known/change-password', | ||
126 | (_, res: express.Response) => { | ||
127 | res.redirect('/my-account/settings') | ||
128 | } | ||
129 | ) | ||
130 | |||
131 | staticRouter.use('/.well-known/host-meta', | ||
132 | (_, res: express.Response) => { | ||
133 | res.type('application/xml') | ||
134 | |||
135 | const xml = '<?xml version="1.0" encoding="UTF-8"?>\n' + | ||
136 | '<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">\n' + | ||
137 | ` <Link rel="lrdd" type="application/xrd+xml" template="${WEBSERVER.URL}/.well-known/webfinger?resource={uri}"/>\n` + | ||
138 | '</XRD>' | ||
139 | |||
140 | res.send(xml).end() | ||
141 | } | ||
142 | ) | ||
143 | |||
144 | // --------------------------------------------------------------------------- | 34 | // --------------------------------------------------------------------------- |
145 | 35 | ||
146 | export { | 36 | export { |
147 | staticRouter | 37 | staticRouter |
148 | } | 38 | } |
149 | |||
150 | // --------------------------------------------------------------------------- | ||
151 | |||
152 | async function generateNodeinfo (req: express.Request, res: express.Response) { | ||
153 | const { totalVideos } = await VideoModel.getStats() | ||
154 | const { totalLocalVideoComments } = await VideoCommentModel.getStats() | ||
155 | const { totalUsers, totalMonthlyActiveUsers, totalHalfYearActiveUsers } = await UserModel.getStats() | ||
156 | |||
157 | if (!req.params.version || req.params.version !== '2.0') { | ||
158 | return res.fail({ | ||
159 | status: HttpStatusCode.NOT_FOUND_404, | ||
160 | message: 'Nodeinfo schema version not handled' | ||
161 | }) | ||
162 | } | ||
163 | |||
164 | const json = { | ||
165 | version: '2.0', | ||
166 | software: { | ||
167 | name: 'peertube', | ||
168 | version: PEERTUBE_VERSION | ||
169 | }, | ||
170 | protocols: [ | ||
171 | 'activitypub' | ||
172 | ], | ||
173 | services: { | ||
174 | inbound: [], | ||
175 | outbound: [ | ||
176 | 'atom1.0', | ||
177 | 'rss2.0' | ||
178 | ] | ||
179 | }, | ||
180 | openRegistrations: CONFIG.SIGNUP.ENABLED, | ||
181 | usage: { | ||
182 | users: { | ||
183 | total: totalUsers, | ||
184 | activeMonth: totalMonthlyActiveUsers, | ||
185 | activeHalfyear: totalHalfYearActiveUsers | ||
186 | }, | ||
187 | localPosts: totalVideos, | ||
188 | localComments: totalLocalVideoComments | ||
189 | }, | ||
190 | metadata: { | ||
191 | taxonomy: { | ||
192 | postsName: 'Videos' | ||
193 | }, | ||
194 | nodeName: CONFIG.INSTANCE.NAME, | ||
195 | nodeDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, | ||
196 | nodeConfig: { | ||
197 | search: { | ||
198 | remoteUri: { | ||
199 | users: CONFIG.SEARCH.REMOTE_URI.USERS, | ||
200 | anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS | ||
201 | } | ||
202 | }, | ||
203 | plugin: { | ||
204 | registered: ServerConfigManager.Instance.getRegisteredPlugins() | ||
205 | }, | ||
206 | theme: { | ||
207 | registered: ServerConfigManager.Instance.getRegisteredThemes(), | ||
208 | default: getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME) | ||
209 | }, | ||
210 | email: { | ||
211 | enabled: isEmailEnabled() | ||
212 | }, | ||
213 | contactForm: { | ||
214 | enabled: CONFIG.CONTACT_FORM.ENABLED | ||
215 | }, | ||
216 | transcoding: { | ||
217 | hls: { | ||
218 | enabled: CONFIG.TRANSCODING.HLS.ENABLED | ||
219 | }, | ||
220 | webtorrent: { | ||
221 | enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED | ||
222 | }, | ||
223 | enabledResolutions: ServerConfigManager.Instance.getEnabledResolutions('vod') | ||
224 | }, | ||
225 | live: { | ||
226 | enabled: CONFIG.LIVE.ENABLED, | ||
227 | transcoding: { | ||
228 | enabled: CONFIG.LIVE.TRANSCODING.ENABLED, | ||
229 | enabledResolutions: ServerConfigManager.Instance.getEnabledResolutions('live') | ||
230 | } | ||
231 | }, | ||
232 | import: { | ||
233 | videos: { | ||
234 | http: { | ||
235 | enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED | ||
236 | }, | ||
237 | torrent: { | ||
238 | enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED | ||
239 | } | ||
240 | } | ||
241 | }, | ||
242 | autoBlacklist: { | ||
243 | videos: { | ||
244 | ofUsers: { | ||
245 | enabled: CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED | ||
246 | } | ||
247 | } | ||
248 | }, | ||
249 | avatar: { | ||
250 | file: { | ||
251 | size: { | ||
252 | max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max | ||
253 | }, | ||
254 | extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME | ||
255 | } | ||
256 | }, | ||
257 | video: { | ||
258 | image: { | ||
259 | extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME, | ||
260 | size: { | ||
261 | max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max | ||
262 | } | ||
263 | }, | ||
264 | file: { | ||
265 | extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME | ||
266 | } | ||
267 | }, | ||
268 | videoCaption: { | ||
269 | file: { | ||
270 | size: { | ||
271 | max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max | ||
272 | }, | ||
273 | extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME | ||
274 | } | ||
275 | }, | ||
276 | user: { | ||
277 | videoQuota: CONFIG.USER.VIDEO_QUOTA, | ||
278 | videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY | ||
279 | }, | ||
280 | trending: { | ||
281 | videos: { | ||
282 | intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS | ||
283 | } | ||
284 | }, | ||
285 | tracker: { | ||
286 | enabled: CONFIG.TRACKER.ENABLED | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | } as HttpNodeinfoDiasporaSoftwareNsSchema20 | ||
291 | |||
292 | res.contentType('application/json; profile="http://nodeinfo.diaspora.software/ns/schema/2.0#"') | ||
293 | .send(json) | ||
294 | .end() | ||
295 | } | ||
296 | |||
297 | function getCup (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
298 | res.status(HttpStatusCode.I_AM_A_TEAPOT_418) | ||
299 | res.setHeader('Accept-Additions', 'Non-Dairy;1,Sugar;1') | ||
300 | res.setHeader('Safe', 'if-sepia-awake') | ||
301 | |||
302 | return next() | ||
303 | } | ||