aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/initializers
diff options
context:
space:
mode:
Diffstat (limited to 'server/initializers')
-rw-r--r--server/initializers/checker-after-init.ts15
-rw-r--r--server/initializers/checker-before-init.ts3
-rw-r--r--server/initializers/config.ts7
-rw-r--r--server/initializers/constants.ts31
-rw-r--r--server/initializers/database.ts6
-rw-r--r--server/initializers/installer.ts6
-rw-r--r--server/initializers/migrations/0750-user-registration.ts58
-rw-r--r--server/initializers/migrations/0755-unique-viewer-url.ts27
8 files changed, 134 insertions, 19 deletions
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts
index c83fef425..0df7414be 100644
--- a/server/initializers/checker-after-init.ts
+++ b/server/initializers/checker-after-init.ts
@@ -4,7 +4,7 @@ import { getFFmpegVersion } from '@server/helpers/ffmpeg'
4import { uniqify } from '@shared/core-utils' 4import { uniqify } from '@shared/core-utils'
5import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type' 5import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type'
6import { RecentlyAddedStrategy } from '../../shared/models/redundancy' 6import { RecentlyAddedStrategy } from '../../shared/models/redundancy'
7import { isProdInstance, parseSemVersion } from '../helpers/core-utils' 7import { isProdInstance, parseBytes, parseSemVersion } from '../helpers/core-utils'
8import { isArray } from '../helpers/custom-validators/misc' 8import { isArray } from '../helpers/custom-validators/misc'
9import { logger } from '../helpers/logger' 9import { logger } from '../helpers/logger'
10import { ApplicationModel, getServerActor } from '../models/application/application' 10import { ApplicationModel, getServerActor } from '../models/application/application'
@@ -116,6 +116,11 @@ function checkEmailConfig () {
116 throw new Error('Emailer is disabled but you require signup email verification.') 116 throw new Error('Emailer is disabled but you require signup email verification.')
117 } 117 }
118 118
119 if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_APPROVAL) {
120 // eslint-disable-next-line max-len
121 logger.warn('Emailer is disabled but signup approval is enabled: PeerTube will not be able to send an email to the user upon acceptance/rejection of the registration request')
122 }
123
119 if (CONFIG.CONTACT_FORM.ENABLED) { 124 if (CONFIG.CONTACT_FORM.ENABLED) {
120 logger.warn('Emailer is disabled so the contact form will not work.') 125 logger.warn('Emailer is disabled so the contact form will not work.')
121 } 126 }
@@ -174,7 +179,8 @@ function checkRemoteRedundancyConfig () {
174function checkStorageConfig () { 179function checkStorageConfig () {
175 // Check storage directory locations 180 // Check storage directory locations
176 if (isProdInstance()) { 181 if (isProdInstance()) {
177 const configStorage = config.get('storage') 182 const configStorage = config.get<{ [ name: string ]: string }>('storage')
183
178 for (const key of Object.keys(configStorage)) { 184 for (const key of Object.keys(configStorage)) {
179 if (configStorage[key].startsWith('storage/')) { 185 if (configStorage[key].startsWith('storage/')) {
180 logger.warn( 186 logger.warn(
@@ -278,6 +284,11 @@ function checkObjectStorageConfig () {
278 'Object storage bucket prefixes should be set to different values when the same bucket is used for both types of video.' 284 'Object storage bucket prefixes should be set to different values when the same bucket is used for both types of video.'
279 ) 285 )
280 } 286 }
287
288 if (CONFIG.OBJECT_STORAGE.MAX_UPLOAD_PART > parseBytes('250MB')) {
289 // eslint-disable-next-line max-len
290 logger.warn(`Object storage max upload part seems to have a big value (${CONFIG.OBJECT_STORAGE.MAX_UPLOAD_PART} bytes). Consider using a lower one (like 100MB).`)
291 }
281 } 292 }
282} 293}
283 294
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts
index 39713a266..8b4d49180 100644
--- a/server/initializers/checker-before-init.ts
+++ b/server/initializers/checker-before-init.ts
@@ -13,6 +13,7 @@ function checkMissedConfig () {
13 'webserver.https', 'webserver.hostname', 'webserver.port', 13 'webserver.https', 'webserver.hostname', 'webserver.port',
14 'secrets.peertube', 14 'secrets.peertube',
15 'trust_proxy', 15 'trust_proxy',
16 'oauth2.token_lifetime.access_token', 'oauth2.token_lifetime.refresh_token',
16 'database.hostname', 'database.port', 'database.username', 'database.password', 'database.pool.max', 17 'database.hostname', 'database.port', 'database.username', 'database.password', 'database.pool.max',
17 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', 18 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address',
18 'email.body.signature', 'email.subject.prefix', 19 'email.body.signature', 'email.subject.prefix',
@@ -27,7 +28,7 @@ function checkMissedConfig () {
27 'csp.enabled', 'csp.report_only', 'csp.report_uri', 28 'csp.enabled', 'csp.report_only', 'csp.report_uri',
28 'security.frameguard.enabled', 29 'security.frameguard.enabled',
29 'cache.previews.size', 'cache.captions.size', 'cache.torrents.size', 'admin.email', 'contact_form.enabled', 30 'cache.previews.size', 'cache.captions.size', 'cache.torrents.size', 'admin.email', 'contact_form.enabled',
30 'signup.enabled', 'signup.limit', 'signup.requires_email_verification', 'signup.minimum_age', 31 'signup.enabled', 'signup.limit', 'signup.requires_approval', 'signup.requires_email_verification', 'signup.minimum_age',
31 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', 32 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist',
32 'redundancy.videos.strategies', 'redundancy.videos.check_interval', 33 'redundancy.videos.strategies', 'redundancy.videos.check_interval',
33 'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled', 34 'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled',
diff --git a/server/initializers/config.ts b/server/initializers/config.ts
index c2f8b19fd..9685e7bfc 100644
--- a/server/initializers/config.ts
+++ b/server/initializers/config.ts
@@ -149,6 +149,12 @@ const CONFIG = {
149 HOSTNAME: config.get<string>('webserver.hostname'), 149 HOSTNAME: config.get<string>('webserver.hostname'),
150 PORT: config.get<number>('webserver.port') 150 PORT: config.get<number>('webserver.port')
151 }, 151 },
152 OAUTH2: {
153 TOKEN_LIFETIME: {
154 ACCESS_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.access_token')),
155 REFRESH_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.refresh_token'))
156 }
157 },
152 RATES_LIMIT: { 158 RATES_LIMIT: {
153 API: { 159 API: {
154 WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.api.window')), 160 WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.api.window')),
@@ -299,6 +305,7 @@ const CONFIG = {
299 }, 305 },
300 SIGNUP: { 306 SIGNUP: {
301 get ENABLED () { return config.get<boolean>('signup.enabled') }, 307 get ENABLED () { return config.get<boolean>('signup.enabled') },
308 get REQUIRES_APPROVAL () { return config.get<boolean>('signup.requires_approval') },
302 get LIMIT () { return config.get<number>('signup.limit') }, 309 get LIMIT () { return config.get<number>('signup.limit') },
303 get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') }, 310 get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') },
304 get MINIMUM_AGE () { return config.get<number>('signup.minimum_age') }, 311 get MINIMUM_AGE () { return config.get<number>('signup.minimum_age') },
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 0e56f0c9f..992c86ed2 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -6,6 +6,7 @@ import { randomInt, root } from '@shared/core-utils'
6import { 6import {
7 AbuseState, 7 AbuseState,
8 JobType, 8 JobType,
9 UserRegistrationState,
9 VideoChannelSyncState, 10 VideoChannelSyncState,
10 VideoImportState, 11 VideoImportState,
11 VideoPrivacy, 12 VideoPrivacy,
@@ -25,7 +26,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
25 26
26// --------------------------------------------------------------------------- 27// ---------------------------------------------------------------------------
27 28
28const LAST_MIGRATION_VERSION = 745 29const LAST_MIGRATION_VERSION = 755
29 30
30// --------------------------------------------------------------------------- 31// ---------------------------------------------------------------------------
31 32
@@ -78,6 +79,8 @@ const SORTABLE_COLUMNS = {
78 ACCOUNT_FOLLOWERS: [ 'createdAt' ], 79 ACCOUNT_FOLLOWERS: [ 'createdAt' ],
79 CHANNEL_FOLLOWERS: [ 'createdAt' ], 80 CHANNEL_FOLLOWERS: [ 'createdAt' ],
80 81
82 USER_REGISTRATIONS: [ 'createdAt', 'state' ],
83
81 VIDEOS: [ 'name', 'duration', 'createdAt', 'publishedAt', 'originallyPublishedAt', 'views', 'likes', 'trending', 'hot', 'best' ], 84 VIDEOS: [ 'name', 'duration', 'createdAt', 'publishedAt', 'originallyPublishedAt', 'views', 'likes', 'trending', 'hot', 'best' ],
82 85
83 // Don't forget to update peertube-search-index with the same values 86 // Don't forget to update peertube-search-index with the same values
@@ -101,11 +104,6 @@ const SORTABLE_COLUMNS = {
101 VIDEO_REDUNDANCIES: [ 'name' ] 104 VIDEO_REDUNDANCIES: [ 'name' ]
102} 105}
103 106
104const OAUTH_LIFETIME = {
105 ACCESS_TOKEN: 3600 * 24, // 1 day, for upload
106 REFRESH_TOKEN: 1209600 // 2 weeks
107}
108
109const ROUTE_CACHE_LIFETIME = { 107const ROUTE_CACHE_LIFETIME = {
110 FEEDS: '15 minutes', 108 FEEDS: '15 minutes',
111 ROBOTS: '2 hours', 109 ROBOTS: '2 hours',
@@ -295,6 +293,10 @@ const CONSTRAINTS_FIELDS = {
295 ABUSE_MESSAGES: { 293 ABUSE_MESSAGES: {
296 MESSAGE: { min: 2, max: 3000 } // Length 294 MESSAGE: { min: 2, max: 3000 } // Length
297 }, 295 },
296 USER_REGISTRATIONS: {
297 REASON_MESSAGE: { min: 2, max: 3000 }, // Length
298 MODERATOR_MESSAGE: { min: 2, max: 3000 } // Length
299 },
298 VIDEO_BLACKLIST: { 300 VIDEO_BLACKLIST: {
299 REASON: { min: 2, max: 300 } // Length 301 REASON: { min: 2, max: 300 } // Length
300 }, 302 },
@@ -521,6 +523,12 @@ const ABUSE_STATES: { [ id in AbuseState ]: string } = {
521 [AbuseState.ACCEPTED]: 'Accepted' 523 [AbuseState.ACCEPTED]: 'Accepted'
522} 524}
523 525
526const USER_REGISTRATION_STATES: { [ id in UserRegistrationState ]: string } = {
527 [UserRegistrationState.PENDING]: 'Pending',
528 [UserRegistrationState.REJECTED]: 'Rejected',
529 [UserRegistrationState.ACCEPTED]: 'Accepted'
530}
531
524const VIDEO_PLAYLIST_PRIVACIES: { [ id in VideoPlaylistPrivacy ]: string } = { 532const VIDEO_PLAYLIST_PRIVACIES: { [ id in VideoPlaylistPrivacy ]: string } = {
525 [VideoPlaylistPrivacy.PUBLIC]: 'Public', 533 [VideoPlaylistPrivacy.PUBLIC]: 'Public',
526 [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted', 534 [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted',
@@ -665,7 +673,7 @@ const USER_PASSWORD_CREATE_LIFETIME = 60000 * 60 * 24 * 7 // 7 days
665 673
666const TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME = 60000 * 10 // 10 minutes 674const TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME = 60000 * 10 // 10 minutes
667 675
668const USER_EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes 676const EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes
669 677
670const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = { 678const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = {
671 DO_NOT_LIST: 'do_not_list', 679 DO_NOT_LIST: 'do_not_list',
@@ -781,6 +789,9 @@ const LRU_CACHE = {
781 VIDEO_TOKENS: { 789 VIDEO_TOKENS: {
782 MAX_SIZE: 100_000, 790 MAX_SIZE: 100_000,
783 TTL: parseDurationToMs('8 hours') 791 TTL: parseDurationToMs('8 hours')
792 },
793 TRACKER_IPS: {
794 MAX_SIZE: 100_000
784 } 795 }
785} 796}
786 797
@@ -884,7 +895,7 @@ const TRACKER_RATE_LIMITS = {
884 INTERVAL: 60000 * 5, // 5 minutes 895 INTERVAL: 60000 * 5, // 5 minutes
885 ANNOUNCES_PER_IP_PER_INFOHASH: 15, // maximum announces per torrent in the interval 896 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 897 ANNOUNCES_PER_IP: 30, // maximum announces for all our torrents in the interval
887 BLOCK_IP_LIFETIME: 60000 * 3 // 3 minutes 898 BLOCK_IP_LIFETIME: parseDurationToMs('3 minutes')
888} 899}
889 900
890const P2P_MEDIA_LOADER_PEER_VERSION = 2 901const P2P_MEDIA_LOADER_PEER_VERSION = 2
@@ -1030,7 +1041,6 @@ export {
1030 JOB_ATTEMPTS, 1041 JOB_ATTEMPTS,
1031 AP_CLEANER, 1042 AP_CLEANER,
1032 LAST_MIGRATION_VERSION, 1043 LAST_MIGRATION_VERSION,
1033 OAUTH_LIFETIME,
1034 CUSTOM_HTML_TAG_COMMENTS, 1044 CUSTOM_HTML_TAG_COMMENTS,
1035 STATS_TIMESERIE, 1045 STATS_TIMESERIE,
1036 BROADCAST_CONCURRENCY, 1046 BROADCAST_CONCURRENCY,
@@ -1072,13 +1082,14 @@ export {
1072 VIDEO_TRANSCODING_FPS, 1082 VIDEO_TRANSCODING_FPS,
1073 FFMPEG_NICE, 1083 FFMPEG_NICE,
1074 ABUSE_STATES, 1084 ABUSE_STATES,
1085 USER_REGISTRATION_STATES,
1075 LRU_CACHE, 1086 LRU_CACHE,
1076 REQUEST_TIMEOUTS, 1087 REQUEST_TIMEOUTS,
1077 MAX_LOCAL_VIEWER_WATCH_SECTIONS, 1088 MAX_LOCAL_VIEWER_WATCH_SECTIONS,
1078 USER_PASSWORD_RESET_LIFETIME, 1089 USER_PASSWORD_RESET_LIFETIME,
1079 USER_PASSWORD_CREATE_LIFETIME, 1090 USER_PASSWORD_CREATE_LIFETIME,
1080 MEMOIZE_TTL, 1091 MEMOIZE_TTL,
1081 USER_EMAIL_VERIFY_LIFETIME, 1092 EMAIL_VERIFY_LIFETIME,
1082 OVERVIEWS, 1093 OVERVIEWS,
1083 SCHEDULER_INTERVALS_MS, 1094 SCHEDULER_INTERVALS_MS,
1084 REPEAT_JOBS, 1095 REPEAT_JOBS,
diff --git a/server/initializers/database.ts b/server/initializers/database.ts
index f55f40df0..96145f489 100644
--- a/server/initializers/database.ts
+++ b/server/initializers/database.ts
@@ -5,7 +5,9 @@ import { TrackerModel } from '@server/models/server/tracker'
5import { VideoTrackerModel } from '@server/models/server/video-tracker' 5import { VideoTrackerModel } from '@server/models/server/video-tracker'
6import { UserModel } from '@server/models/user/user' 6import { UserModel } from '@server/models/user/user'
7import { UserNotificationModel } from '@server/models/user/user-notification' 7import { UserNotificationModel } from '@server/models/user/user-notification'
8import { UserRegistrationModel } from '@server/models/user/user-registration'
8import { UserVideoHistoryModel } from '@server/models/user/user-video-history' 9import { UserVideoHistoryModel } from '@server/models/user/user-video-history'
10import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync'
9import { VideoJobInfoModel } from '@server/models/video/video-job-info' 11import { VideoJobInfoModel } from '@server/models/video/video-job-info'
10import { VideoLiveSessionModel } from '@server/models/video/video-live-session' 12import { VideoLiveSessionModel } from '@server/models/video/video-live-session'
11import { VideoSourceModel } from '@server/models/video/video-source' 13import { VideoSourceModel } from '@server/models/video/video-source'
@@ -50,7 +52,6 @@ import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-pla
50import { VideoTagModel } from '../models/video/video-tag' 52import { VideoTagModel } from '../models/video/video-tag'
51import { VideoViewModel } from '../models/view/video-view' 53import { VideoViewModel } from '../models/view/video-view'
52import { CONFIG } from './config' 54import { CONFIG } from './config'
53import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync'
54 55
55require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string 56require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
56 57
@@ -155,7 +156,8 @@ async function initDatabaseModels (silent: boolean) {
155 PluginModel, 156 PluginModel,
156 ActorCustomPageModel, 157 ActorCustomPageModel,
157 VideoJobInfoModel, 158 VideoJobInfoModel,
158 VideoChannelSyncModel 159 VideoChannelSyncModel,
160 UserRegistrationModel
159 ]) 161 ])
160 162
161 // Check extensions exist in the database 163 // Check extensions exist in the database
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts
index f5d8eedf1..f48f348a7 100644
--- a/server/initializers/installer.ts
+++ b/server/initializers/installer.ts
@@ -51,8 +51,7 @@ function removeCacheAndTmpDirectories () {
51 const tasks: Promise<any>[] = [] 51 const tasks: Promise<any>[] = []
52 52
53 // Cache directories 53 // Cache directories
54 for (const key of Object.keys(cacheDirectories)) { 54 for (const dir of cacheDirectories) {
55 const dir = cacheDirectories[key]
56 tasks.push(removeDirectoryOrContent(dir)) 55 tasks.push(removeDirectoryOrContent(dir))
57 } 56 }
58 57
@@ -87,8 +86,7 @@ function createDirectoriesIfNotExist () {
87 } 86 }
88 87
89 // Cache directories 88 // Cache directories
90 for (const key of Object.keys(cacheDirectories)) { 89 for (const dir of cacheDirectories) {
91 const dir = cacheDirectories[key]
92 tasks.push(ensureDir(dir)) 90 tasks.push(ensureDir(dir))
93 } 91 }
94 92
diff --git a/server/initializers/migrations/0750-user-registration.ts b/server/initializers/migrations/0750-user-registration.ts
new file mode 100644
index 000000000..15bbfd3fd
--- /dev/null
+++ b/server/initializers/migrations/0750-user-registration.ts
@@ -0,0 +1,58 @@
1
2import * as Sequelize from 'sequelize'
3
4async function up (utils: {
5 transaction: Sequelize.Transaction
6 queryInterface: Sequelize.QueryInterface
7 sequelize: Sequelize.Sequelize
8 db: any
9}): Promise<void> {
10 {
11 const query = `
12 CREATE TABLE IF NOT EXISTS "userRegistration" (
13 "id" serial,
14 "state" integer NOT NULL,
15 "registrationReason" text NOT NULL,
16 "moderationResponse" text,
17 "password" varchar(255),
18 "username" varchar(255) NOT NULL,
19 "email" varchar(400) NOT NULL,
20 "emailVerified" boolean,
21 "accountDisplayName" varchar(255),
22 "channelHandle" varchar(255),
23 "channelDisplayName" varchar(255),
24 "userId" integer REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
25 "createdAt" timestamp with time zone NOT NULL,
26 "updatedAt" timestamp with time zone NOT NULL,
27 PRIMARY KEY ("id")
28 );
29 `
30 await utils.sequelize.query(query, { transaction: utils.transaction })
31 }
32
33 {
34 await utils.queryInterface.addColumn('userNotification', 'userRegistrationId', {
35 type: Sequelize.INTEGER,
36 defaultValue: null,
37 allowNull: true,
38 references: {
39 model: 'userRegistration',
40 key: 'id'
41 },
42 onUpdate: 'CASCADE',
43 onDelete: 'SET NULL'
44 }, { transaction: utils.transaction })
45 }
46}
47
48async function down (utils: {
49 queryInterface: Sequelize.QueryInterface
50 transaction: Sequelize.Transaction
51}) {
52 await utils.queryInterface.dropTable('videoChannelSync', { transaction: utils.transaction })
53}
54
55export {
56 up,
57 down
58}
diff --git a/server/initializers/migrations/0755-unique-viewer-url.ts b/server/initializers/migrations/0755-unique-viewer-url.ts
new file mode 100644
index 000000000..b3dff9258
--- /dev/null
+++ b/server/initializers/migrations/0755-unique-viewer-url.ts
@@ -0,0 +1,27 @@
1import * as Sequelize from 'sequelize'
2
3async function up (utils: {
4 transaction: Sequelize.Transaction
5 queryInterface: Sequelize.QueryInterface
6 sequelize: Sequelize.Sequelize
7 db: any
8}): Promise<void> {
9 const { transaction } = utils
10
11 const query = 'DELETE FROM "localVideoViewer" t1 ' +
12 'USING (SELECT MIN(id) as id, "url" FROM "localVideoViewer" GROUP BY "url" HAVING COUNT(*) > 1) t2 ' +
13 'WHERE t1."url" = t2."url" AND t1.id <> t2.id'
14
15 await utils.sequelize.query(query, { transaction })
16}
17
18async function down (utils: {
19 queryInterface: Sequelize.QueryInterface
20 transaction: Sequelize.Transaction
21}) {
22}
23
24export {
25 up,
26 down
27}