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.ts10
-rw-r--r--server/initializers/config.ts20
-rw-r--r--server/initializers/constants.ts68
-rw-r--r--server/initializers/installer.ts10
-rw-r--r--server/initializers/migrations/0745-user-otp.ts29
6 files changed, 135 insertions, 17 deletions
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts
index 42839d1c9..09e878eee 100644
--- a/server/initializers/checker-after-init.ts
+++ b/server/initializers/checker-after-init.ts
@@ -42,6 +42,7 @@ function checkConfig () {
42 logger.warn('services.csp-logger configuration has been renamed to csp.report_uri. Please update your configuration file.') 42 logger.warn('services.csp-logger configuration has been renamed to csp.report_uri. Please update your configuration file.')
43 } 43 }
44 44
45 checkSecretsConfig()
45 checkEmailConfig() 46 checkEmailConfig()
46 checkNSFWPolicyConfig() 47 checkNSFWPolicyConfig()
47 checkLocalRedundancyConfig() 48 checkLocalRedundancyConfig()
@@ -103,6 +104,12 @@ export {
103 104
104// --------------------------------------------------------------------------- 105// ---------------------------------------------------------------------------
105 106
107function checkSecretsConfig () {
108 if (!CONFIG.SECRETS.PEERTUBE) {
109 throw new Error('secrets.peertube is missing in config. Generate one using `openssl rand -hex 32`')
110 }
111}
112
106function checkEmailConfig () { 113function checkEmailConfig () {
107 if (!isEmailEnabled()) { 114 if (!isEmailEnabled()) {
108 if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { 115 if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
@@ -271,6 +278,14 @@ function checkObjectStorageConfig () {
271 'Object storage bucket prefixes should be set to different values when the same bucket is used for both types of video.' 278 'Object storage bucket prefixes should be set to different values when the same bucket is used for both types of video.'
272 ) 279 )
273 } 280 }
281
282 if (!CONFIG.OBJECT_STORAGE.UPLOAD_ACL.PUBLIC) {
283 throw new Error('object_storage.upload_acl.public must be set')
284 }
285
286 if (!CONFIG.OBJECT_STORAGE.UPLOAD_ACL.PRIVATE) {
287 throw new Error('object_storage.upload_acl.private must be set')
288 }
274 } 289 }
275} 290}
276 291
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts
index 3188903be..42be7ee6e 100644
--- a/server/initializers/checker-before-init.ts
+++ b/server/initializers/checker-before-init.ts
@@ -11,12 +11,13 @@ const config: IConfig = require('config')
11function checkMissedConfig () { 11function checkMissedConfig () {
12 const required = [ 'listen.port', 'listen.hostname', 12 const required = [ 'listen.port', 'listen.hostname',
13 'webserver.https', 'webserver.hostname', 'webserver.port', 13 'webserver.https', 'webserver.hostname', 'webserver.port',
14 'secrets.peertube',
14 'trust_proxy', 15 'trust_proxy',
15 'database.hostname', 'database.port', 'database.username', 'database.password', 'database.pool.max', 16 'database.hostname', 'database.port', 'database.username', 'database.password', 'database.pool.max',
16 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', 17 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address',
17 'email.body.signature', 'email.subject.prefix', 18 'email.body.signature', 'email.subject.prefix',
18 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache', 19 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache',
19 'storage.redundancy', 'storage.tmp', 'storage.streaming_playlists', 'storage.plugins', 20 'storage.redundancy', 'storage.tmp', 'storage.streaming_playlists', 'storage.plugins', 'storage.well_known',
20 'log.level', 21 'log.level',
21 'user.video_quota', 'user.video_quota_daily', 22 'user.video_quota', 'user.video_quota_daily',
22 'video_channels.max_per_user', 23 'video_channels.max_per_user',
@@ -34,6 +35,7 @@ function checkMissedConfig () {
34 'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'import.videos.timeout', 35 'import.videos.http.enabled', 'import.videos.torrent.enabled', 'import.videos.concurrency', 'import.videos.timeout',
35 'import.video_channel_synchronization.enabled', 'import.video_channel_synchronization.max_per_user', 36 'import.video_channel_synchronization.enabled', 'import.video_channel_synchronization.max_per_user',
36 'import.video_channel_synchronization.check_interval', 'import.video_channel_synchronization.videos_limit_per_synchronization', 37 'import.video_channel_synchronization.check_interval', 'import.video_channel_synchronization.videos_limit_per_synchronization',
38 'import.video_channel_synchronization.full_sync_videos_limit',
37 'auto_blacklist.videos.of_users.enabled', 'trending.videos.interval_days', 39 'auto_blacklist.videos.of_users.enabled', 'trending.videos.interval_days',
38 'client.videos.miniature.display_author_avatar', 40 'client.videos.miniature.display_author_avatar',
39 'client.videos.miniature.prefer_author_display_name', 'client.menu.login.redirect_on_single_external_auth', 41 'client.videos.miniature.prefer_author_display_name', 'client.menu.login.redirect_on_single_external_auth',
@@ -45,6 +47,12 @@ function checkMissedConfig () {
45 'tracker.enabled', 'tracker.private', 'tracker.reject_too_many_announces', 47 'tracker.enabled', 'tracker.private', 'tracker.reject_too_many_announces',
46 'history.videos.max_age', 'views.videos.remote.max_age', 'views.videos.local_buffer_update_interval', 'views.videos.ip_view_expiration', 48 'history.videos.max_age', 'views.videos.remote.max_age', 'views.videos.local_buffer_update_interval', 'views.videos.ip_view_expiration',
47 'rates_limit.login.window', 'rates_limit.login.max', 'rates_limit.ask_send_email.window', 'rates_limit.ask_send_email.max', 49 'rates_limit.login.window', 'rates_limit.login.max', 'rates_limit.ask_send_email.window', 'rates_limit.ask_send_email.max',
50 'static_files.private_files_require_auth',
51 'object_storage.enabled', 'object_storage.endpoint', 'object_storage.region', 'object_storage.upload_acl.public',
52 'object_storage.upload_acl.private', 'object_storage.proxy.proxify_private_files', 'object_storage.credentials.access_key_id',
53 'object_storage.credentials.secret_access_key', 'object_storage.max_upload_part', 'object_storage.streaming_playlists.bucket_name',
54 'object_storage.streaming_playlists.prefix', 'object_storage.streaming_playlists.base_url', 'object_storage.videos.bucket_name',
55 'object_storage.videos.prefix', 'object_storage.videos.base_url',
48 'theme.default', 56 'theme.default',
49 'feeds.videos.count', 'feeds.comments.count', 57 'feeds.videos.count', 'feeds.comments.count',
50 'geo_ip.enabled', 'geo_ip.country.database_url', 58 'geo_ip.enabled', 'geo_ip.country.database_url',
diff --git a/server/initializers/config.ts b/server/initializers/config.ts
index 2c92bea22..3dd1f6971 100644
--- a/server/initializers/config.ts
+++ b/server/initializers/config.ts
@@ -20,6 +20,9 @@ const CONFIG = {
20 PORT: config.get<number>('listen.port'), 20 PORT: config.get<number>('listen.port'),
21 HOSTNAME: config.get<string>('listen.hostname') 21 HOSTNAME: config.get<string>('listen.hostname')
22 }, 22 },
23 SECRETS: {
24 PEERTUBE: config.get<string>('secrets.peertube')
25 },
23 DATABASE: { 26 DATABASE: {
24 DBNAME: config.has('database.name') ? config.get<string>('database.name') : 'peertube' + config.get<string>('database.suffix'), 27 DBNAME: config.has('database.name') ? config.get<string>('database.name') : 'peertube' + config.get<string>('database.suffix'),
25 HOSTNAME: config.get<string>('database.hostname'), 28 HOSTNAME: config.get<string>('database.hostname'),
@@ -107,18 +110,28 @@ const CONFIG = {
107 TORRENTS_DIR: buildPath(config.get<string>('storage.torrents')), 110 TORRENTS_DIR: buildPath(config.get<string>('storage.torrents')),
108 CACHE_DIR: buildPath(config.get<string>('storage.cache')), 111 CACHE_DIR: buildPath(config.get<string>('storage.cache')),
109 PLUGINS_DIR: buildPath(config.get<string>('storage.plugins')), 112 PLUGINS_DIR: buildPath(config.get<string>('storage.plugins')),
110 CLIENT_OVERRIDES_DIR: buildPath(config.get<string>('storage.client_overrides')) 113 CLIENT_OVERRIDES_DIR: buildPath(config.get<string>('storage.client_overrides')),
114 WELL_KNOWN_DIR: buildPath(config.get<string>('storage.well_known'))
115 },
116 STATIC_FILES: {
117 PRIVATE_FILES_REQUIRE_AUTH: config.get<boolean>('static_files.private_files_require_auth')
111 }, 118 },
112 OBJECT_STORAGE: { 119 OBJECT_STORAGE: {
113 ENABLED: config.get<boolean>('object_storage.enabled'), 120 ENABLED: config.get<boolean>('object_storage.enabled'),
114 MAX_UPLOAD_PART: bytes.parse(config.get<string>('object_storage.max_upload_part')), 121 MAX_UPLOAD_PART: bytes.parse(config.get<string>('object_storage.max_upload_part')),
115 ENDPOINT: config.get<string>('object_storage.endpoint'), 122 ENDPOINT: config.get<string>('object_storage.endpoint'),
116 REGION: config.get<string>('object_storage.region'), 123 REGION: config.get<string>('object_storage.region'),
117 UPLOAD_ACL: config.get<string>('object_storage.upload_acl'), 124 UPLOAD_ACL: {
125 PUBLIC: config.get<string>('object_storage.upload_acl.public'),
126 PRIVATE: config.get<string>('object_storage.upload_acl.private')
127 },
118 CREDENTIALS: { 128 CREDENTIALS: {
119 ACCESS_KEY_ID: config.get<string>('object_storage.credentials.access_key_id'), 129 ACCESS_KEY_ID: config.get<string>('object_storage.credentials.access_key_id'),
120 SECRET_ACCESS_KEY: config.get<string>('object_storage.credentials.secret_access_key') 130 SECRET_ACCESS_KEY: config.get<string>('object_storage.credentials.secret_access_key')
121 }, 131 },
132 PROXY: {
133 PROXIFY_PRIVATE_FILES: config.get<boolean>('object_storage.proxy.proxify_private_files')
134 },
122 VIDEOS: { 135 VIDEOS: {
123 BUCKET_NAME: config.get<string>('object_storage.videos.bucket_name'), 136 BUCKET_NAME: config.get<string>('object_storage.videos.bucket_name'),
124 PREFIX: config.get<string>('object_storage.videos.prefix'), 137 PREFIX: config.get<string>('object_storage.videos.prefix'),
@@ -405,6 +418,9 @@ const CONFIG = {
405 get CHECK_INTERVAL () { return parseDurationToMs(config.get<string>('import.video_channel_synchronization.check_interval')) }, 418 get CHECK_INTERVAL () { return parseDurationToMs(config.get<string>('import.video_channel_synchronization.check_interval')) },
406 get VIDEOS_LIMIT_PER_SYNCHRONIZATION () { 419 get VIDEOS_LIMIT_PER_SYNCHRONIZATION () {
407 return config.get<number>('import.video_channel_synchronization.videos_limit_per_synchronization') 420 return config.get<number>('import.video_channel_synchronization.videos_limit_per_synchronization')
421 },
422 get FULL_SYNC_VIDEOS_LIMIT () {
423 return config.get<number>('import.video_channel_synchronization.full_sync_videos_limit')
408 } 424 }
409 } 425 }
410 }, 426 },
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 7039ab457..66eb31230 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -1,5 +1,5 @@
1import { RepeatOptions } from 'bullmq' 1import { RepeatOptions } from 'bullmq'
2import { randomBytes } from 'crypto' 2import { Encoding, randomBytes } from 'crypto'
3import { invert } from 'lodash' 3import { invert } from 'lodash'
4import { join } from 'path' 4import { join } from 'path'
5import { randomInt, root } from '@shared/core-utils' 5import { randomInt, root } from '@shared/core-utils'
@@ -25,7 +25,7 @@ import { CONFIG, registerConfigChangedHandler } from './config'
25 25
26// --------------------------------------------------------------------------- 26// ---------------------------------------------------------------------------
27 27
28const LAST_MIGRATION_VERSION = 740 28const LAST_MIGRATION_VERSION = 745
29 29
30// --------------------------------------------------------------------------- 30// ---------------------------------------------------------------------------
31 31
@@ -116,7 +116,8 @@ const ROUTE_CACHE_LIFETIME = {
116 ACTIVITY_PUB: { 116 ACTIVITY_PUB: {
117 VIDEOS: '1 second' // 1 second, cache concurrent requests after a broadcast for example 117 VIDEOS: '1 second' // 1 second, cache concurrent requests after a broadcast for example
118 }, 118 },
119 STATS: '4 hours' 119 STATS: '4 hours',
120 WELL_KNOWN: '1 day'
120} 121}
121 122
122// --------------------------------------------------------------------------- 123// ---------------------------------------------------------------------------
@@ -636,9 +637,18 @@ let PRIVATE_RSA_KEY_SIZE = 2048
636// Password encryption 637// Password encryption
637const BCRYPT_SALT_SIZE = 10 638const BCRYPT_SALT_SIZE = 10
638 639
640const ENCRYPTION = {
641 ALGORITHM: 'aes-256-cbc',
642 IV: 16,
643 SALT: 'peertube',
644 ENCODING: 'hex' as Encoding
645}
646
639const USER_PASSWORD_RESET_LIFETIME = 60000 * 60 // 60 minutes 647const USER_PASSWORD_RESET_LIFETIME = 60000 * 60 // 60 minutes
640const USER_PASSWORD_CREATE_LIFETIME = 60000 * 60 * 24 * 7 // 7 days 648const USER_PASSWORD_CREATE_LIFETIME = 60000 * 60 * 24 * 7 // 7 days
641 649
650const TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME = 60000 * 10 // 10 minutes
651
642const USER_EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes 652const USER_EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes
643 653
644const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = { 654const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = {
@@ -652,10 +662,15 @@ const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = {
652// Express static paths (router) 662// Express static paths (router)
653const STATIC_PATHS = { 663const STATIC_PATHS = {
654 THUMBNAILS: '/static/thumbnails/', 664 THUMBNAILS: '/static/thumbnails/',
665
655 WEBSEED: '/static/webseed/', 666 WEBSEED: '/static/webseed/',
667 PRIVATE_WEBSEED: '/static/webseed/private/',
668
656 REDUNDANCY: '/static/redundancy/', 669 REDUNDANCY: '/static/redundancy/',
670
657 STREAMING_PLAYLISTS: { 671 STREAMING_PLAYLISTS: {
658 HLS: '/static/streaming-playlists/hls' 672 HLS: '/static/streaming-playlists/hls',
673 PRIVATE_HLS: '/static/streaming-playlists/hls/private/'
659 } 674 }
660} 675}
661const STATIC_DOWNLOAD_PATHS = { 676const STATIC_DOWNLOAD_PATHS = {
@@ -670,6 +685,13 @@ const LAZY_STATIC_PATHS = {
670 VIDEO_CAPTIONS: '/lazy-static/video-captions/', 685 VIDEO_CAPTIONS: '/lazy-static/video-captions/',
671 TORRENTS: '/lazy-static/torrents/' 686 TORRENTS: '/lazy-static/torrents/'
672} 687}
688const OBJECT_STORAGE_PROXY_PATHS = {
689 PRIVATE_WEBSEED: '/object-storage-proxy/webseed/private/',
690
691 STREAMING_PLAYLISTS: {
692 PRIVATE_HLS: '/object-storage-proxy/streaming-playlists/hls/private/'
693 }
694}
673 695
674// Cache control 696// Cache control
675const STATIC_MAX_AGE = { 697const STATIC_MAX_AGE = {
@@ -735,12 +757,32 @@ const LRU_CACHE = {
735 }, 757 },
736 ACTOR_IMAGE_STATIC: { 758 ACTOR_IMAGE_STATIC: {
737 MAX_SIZE: 500 759 MAX_SIZE: 500
760 },
761 STATIC_VIDEO_FILES_RIGHTS_CHECK: {
762 MAX_SIZE: 5000,
763 TTL: parseDurationToMs('10 seconds')
764 },
765 VIDEO_TOKENS: {
766 MAX_SIZE: 100_000,
767 TTL: parseDurationToMs('8 hours')
738 } 768 }
739} 769}
740 770
741const RESUMABLE_UPLOAD_DIRECTORY = join(CONFIG.STORAGE.TMP_DIR, 'resumable-uploads') 771const DIRECTORIES = {
742const HLS_STREAMING_PLAYLIST_DIRECTORY = join(CONFIG.STORAGE.STREAMING_PLAYLISTS_DIR, 'hls') 772 RESUMABLE_UPLOAD: join(CONFIG.STORAGE.TMP_DIR, 'resumable-uploads'),
743const HLS_REDUNDANCY_DIRECTORY = join(CONFIG.STORAGE.REDUNDANCY_DIR, 'hls') 773
774 HLS_STREAMING_PLAYLIST: {
775 PUBLIC: join(CONFIG.STORAGE.STREAMING_PLAYLISTS_DIR, 'hls'),
776 PRIVATE: join(CONFIG.STORAGE.STREAMING_PLAYLISTS_DIR, 'hls', 'private')
777 },
778
779 VIDEOS: {
780 PUBLIC: CONFIG.STORAGE.VIDEOS_DIR,
781 PRIVATE: join(CONFIG.STORAGE.VIDEOS_DIR, 'private')
782 },
783
784 HLS_REDUNDANCY: join(CONFIG.STORAGE.REDUNDANCY_DIR, 'hls')
785}
744 786
745const RESUMABLE_UPLOAD_SESSION_LIFETIME = SCHEDULER_INTERVALS_MS.REMOVE_DANGLING_RESUMABLE_UPLOADS 787const RESUMABLE_UPLOAD_SESSION_LIFETIME = SCHEDULER_INTERVALS_MS.REMOVE_DANGLING_RESUMABLE_UPLOADS
746 788
@@ -804,6 +846,10 @@ const REDUNDANCY = {
804} 846}
805 847
806const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS) 848const ACCEPT_HEADERS = [ 'html', 'application/json' ].concat(ACTIVITY_PUB.POTENTIAL_ACCEPT_HEADERS)
849const OTP = {
850 HEADER_NAME: 'x-peertube-otp',
851 HEADER_REQUIRED_VALUE: 'required; app'
852}
807 853
808const ASSETS_PATH = { 854const ASSETS_PATH = {
809 DEFAULT_AUDIO_BACKGROUND: join(root(), 'dist', 'server', 'assets', 'default-audio-background.jpg'), 855 DEFAULT_AUDIO_BACKGROUND: join(root(), 'dist', 'server', 'assets', 'default-audio-background.jpg'),
@@ -952,13 +998,14 @@ const VIDEO_FILTERS = {
952export { 998export {
953 WEBSERVER, 999 WEBSERVER,
954 API_VERSION, 1000 API_VERSION,
1001 ENCRYPTION,
955 VIDEO_LIVE, 1002 VIDEO_LIVE,
956 PEERTUBE_VERSION, 1003 PEERTUBE_VERSION,
957 LAZY_STATIC_PATHS, 1004 LAZY_STATIC_PATHS,
1005 OBJECT_STORAGE_PROXY_PATHS,
958 SEARCH_INDEX, 1006 SEARCH_INDEX,
959 RESUMABLE_UPLOAD_DIRECTORY, 1007 DIRECTORIES,
960 RESUMABLE_UPLOAD_SESSION_LIFETIME, 1008 RESUMABLE_UPLOAD_SESSION_LIFETIME,
961 HLS_REDUNDANCY_DIRECTORY,
962 P2P_MEDIA_LOADER_PEER_VERSION, 1009 P2P_MEDIA_LOADER_PEER_VERSION,
963 ACTOR_IMAGES_SIZE, 1010 ACTOR_IMAGES_SIZE,
964 ACCEPT_HEADERS, 1011 ACCEPT_HEADERS,
@@ -985,13 +1032,13 @@ export {
985 FOLLOW_STATES, 1032 FOLLOW_STATES,
986 DEFAULT_USER_THEME_NAME, 1033 DEFAULT_USER_THEME_NAME,
987 SERVER_ACTOR_NAME, 1034 SERVER_ACTOR_NAME,
1035 TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME,
988 PLUGIN_GLOBAL_CSS_FILE_NAME, 1036 PLUGIN_GLOBAL_CSS_FILE_NAME,
989 PLUGIN_GLOBAL_CSS_PATH, 1037 PLUGIN_GLOBAL_CSS_PATH,
990 PRIVATE_RSA_KEY_SIZE, 1038 PRIVATE_RSA_KEY_SIZE,
991 VIDEO_FILTERS, 1039 VIDEO_FILTERS,
992 ROUTE_CACHE_LIFETIME, 1040 ROUTE_CACHE_LIFETIME,
993 SORTABLE_COLUMNS, 1041 SORTABLE_COLUMNS,
994 HLS_STREAMING_PLAYLIST_DIRECTORY,
995 JOB_TTL, 1042 JOB_TTL,
996 DEFAULT_THEME_NAME, 1043 DEFAULT_THEME_NAME,
997 NSFW_POLICY_TYPES, 1044 NSFW_POLICY_TYPES,
@@ -1040,6 +1087,7 @@ export {
1040 PLUGIN_EXTERNAL_AUTH_TOKEN_LIFETIME, 1087 PLUGIN_EXTERNAL_AUTH_TOKEN_LIFETIME,
1041 ASSETS_PATH, 1088 ASSETS_PATH,
1042 FILES_CONTENT_HASH, 1089 FILES_CONTENT_HASH,
1090 OTP,
1043 loadLanguages, 1091 loadLanguages,
1044 buildLanguages, 1092 buildLanguages,
1045 generateContentHash 1093 generateContentHash
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts
index b02be9567..f5d8eedf1 100644
--- a/server/initializers/installer.ts
+++ b/server/initializers/installer.ts
@@ -10,7 +10,7 @@ import { ApplicationModel } from '../models/application/application'
10import { OAuthClientModel } from '../models/oauth/oauth-client' 10import { OAuthClientModel } from '../models/oauth/oauth-client'
11import { applicationExist, clientsExist, usersExist } from './checker-after-init' 11import { applicationExist, clientsExist, usersExist } from './checker-after-init'
12import { CONFIG } from './config' 12import { CONFIG } from './config'
13import { FILES_CACHE, HLS_STREAMING_PLAYLIST_DIRECTORY, LAST_MIGRATION_VERSION, RESUMABLE_UPLOAD_DIRECTORY } from './constants' 13import { DIRECTORIES, FILES_CACHE, LAST_MIGRATION_VERSION } from './constants'
14import { sequelizeTypescript } from './database' 14import { sequelizeTypescript } from './database'
15 15
16async function installApplication () { 16async function installApplication () {
@@ -92,11 +92,13 @@ function createDirectoriesIfNotExist () {
92 tasks.push(ensureDir(dir)) 92 tasks.push(ensureDir(dir))
93 } 93 }
94 94
95 // Playlist directories 95 tasks.push(ensureDir(DIRECTORIES.HLS_STREAMING_PLAYLIST.PRIVATE))
96 tasks.push(ensureDir(HLS_STREAMING_PLAYLIST_DIRECTORY)) 96 tasks.push(ensureDir(DIRECTORIES.HLS_STREAMING_PLAYLIST.PUBLIC))
97 tasks.push(ensureDir(DIRECTORIES.VIDEOS.PUBLIC))
98 tasks.push(ensureDir(DIRECTORIES.VIDEOS.PRIVATE))
97 99
98 // Resumable upload directory 100 // Resumable upload directory
99 tasks.push(ensureDir(RESUMABLE_UPLOAD_DIRECTORY)) 101 tasks.push(ensureDir(DIRECTORIES.RESUMABLE_UPLOAD))
100 102
101 return Promise.all(tasks) 103 return Promise.all(tasks)
102} 104}
diff --git a/server/initializers/migrations/0745-user-otp.ts b/server/initializers/migrations/0745-user-otp.ts
new file mode 100644
index 000000000..157308ea1
--- /dev/null
+++ b/server/initializers/migrations/0745-user-otp.ts
@@ -0,0 +1,29 @@
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 data = {
12 type: Sequelize.STRING,
13 defaultValue: null,
14 allowNull: true
15 }
16 await utils.queryInterface.addColumn('user', 'otpSecret', data, { transaction })
17
18}
19
20async function down (utils: {
21 queryInterface: Sequelize.QueryInterface
22 transaction: Sequelize.Transaction
23}) {
24}
25
26export {
27 up,
28 down
29}