Mirror of PeerTube
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

config.ts 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. import { IConfig } from 'config'
  2. import { dirname, join } from 'path'
  3. import { VideosRedundancy } from '../../shared/models'
  4. // Do not use barrels, remain constants as independent as possible
  5. import { buildPath, parseBytes, parseDurationToMs, root } from '../helpers/core-utils'
  6. import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
  7. import * as bytes from 'bytes'
  8. // Use a variable to reload the configuration if we need
  9. let config: IConfig = require('config')
  10. const configChangedHandlers: Function[] = []
  11. const CONFIG = {
  12. CUSTOM_FILE: getLocalConfigFilePath(),
  13. LISTEN: {
  14. PORT: config.get<number>('listen.port'),
  15. HOSTNAME: config.get<string>('listen.hostname')
  16. },
  17. DATABASE: {
  18. DBNAME: 'peertube' + config.get<string>('database.suffix'),
  19. HOSTNAME: config.get<string>('database.hostname'),
  20. PORT: config.get<number>('database.port'),
  21. USERNAME: config.get<string>('database.username'),
  22. PASSWORD: config.get<string>('database.password'),
  23. POOL: {
  24. MAX: config.get<number>('database.pool.max')
  25. }
  26. },
  27. REDIS: {
  28. HOSTNAME: config.has('redis.hostname') ? config.get<string>('redis.hostname') : null,
  29. PORT: config.has('redis.port') ? config.get<number>('redis.port') : null,
  30. SOCKET: config.has('redis.socket') ? config.get<string>('redis.socket') : null,
  31. AUTH: config.has('redis.auth') ? config.get<string>('redis.auth') : null,
  32. DB: config.has('redis.db') ? config.get<number>('redis.db') : null
  33. },
  34. SMTP: {
  35. HOSTNAME: config.get<string>('smtp.hostname'),
  36. PORT: config.get<number>('smtp.port'),
  37. USERNAME: config.get<string>('smtp.username'),
  38. PASSWORD: config.get<string>('smtp.password'),
  39. TLS: config.get<boolean>('smtp.tls'),
  40. DISABLE_STARTTLS: config.get<boolean>('smtp.disable_starttls'),
  41. CA_FILE: config.get<string>('smtp.ca_file'),
  42. FROM_ADDRESS: config.get<string>('smtp.from_address')
  43. },
  44. EMAIL: {
  45. BODY: {
  46. SIGNATURE: config.get<string>('email.body.signature')
  47. },
  48. SUBJECT: {
  49. PREFIX: config.get<string>('email.subject.prefix') + ' '
  50. }
  51. },
  52. STORAGE: {
  53. TMP_DIR: buildPath(config.get<string>('storage.tmp')),
  54. AVATARS_DIR: buildPath(config.get<string>('storage.avatars')),
  55. LOG_DIR: buildPath(config.get<string>('storage.logs')),
  56. VIDEOS_DIR: buildPath(config.get<string>('storage.videos')),
  57. STREAMING_PLAYLISTS_DIR: buildPath(config.get<string>('storage.streaming_playlists')),
  58. REDUNDANCY_DIR: buildPath(config.get<string>('storage.redundancy')),
  59. THUMBNAILS_DIR: buildPath(config.get<string>('storage.thumbnails')),
  60. PREVIEWS_DIR: buildPath(config.get<string>('storage.previews')),
  61. CAPTIONS_DIR: buildPath(config.get<string>('storage.captions')),
  62. TORRENTS_DIR: buildPath(config.get<string>('storage.torrents')),
  63. CACHE_DIR: buildPath(config.get<string>('storage.cache')),
  64. PLUGINS_DIR: buildPath(config.get<string>('storage.plugins'))
  65. },
  66. WEBSERVER: {
  67. SCHEME: config.get<boolean>('webserver.https') === true ? 'https' : 'http',
  68. WS: config.get<boolean>('webserver.https') === true ? 'wss' : 'ws',
  69. HOSTNAME: config.get<string>('webserver.hostname'),
  70. PORT: config.get<number>('webserver.port')
  71. },
  72. RATES_LIMIT: {
  73. API: {
  74. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.api.window')),
  75. MAX: config.get<number>('rates_limit.api.max')
  76. },
  77. SIGNUP: {
  78. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.signup.window')),
  79. MAX: config.get<number>('rates_limit.signup.max')
  80. },
  81. LOGIN: {
  82. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.login.window')),
  83. MAX: config.get<number>('rates_limit.login.max')
  84. },
  85. ASK_SEND_EMAIL: {
  86. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.ask_send_email.window')),
  87. MAX: config.get<number>('rates_limit.ask_send_email.max')
  88. }
  89. },
  90. TRUST_PROXY: config.get<string[]>('trust_proxy'),
  91. LOG: {
  92. LEVEL: config.get<string>('log.level'),
  93. ROTATION: config.get<boolean>('log.rotation.enabled')
  94. },
  95. SEARCH: {
  96. REMOTE_URI: {
  97. USERS: config.get<boolean>('search.remote_uri.users'),
  98. ANONYMOUS: config.get<boolean>('search.remote_uri.anonymous')
  99. }
  100. },
  101. TRENDING: {
  102. VIDEOS: {
  103. INTERVAL_DAYS: config.get<number>('trending.videos.interval_days')
  104. }
  105. },
  106. REDUNDANCY: {
  107. VIDEOS: {
  108. CHECK_INTERVAL: parseDurationToMs(config.get<string>('redundancy.videos.check_interval')),
  109. STRATEGIES: buildVideosRedundancy(config.get<any[]>('redundancy.videos.strategies'))
  110. }
  111. },
  112. CSP: {
  113. ENABLED: config.get<boolean>('csp.enabled'),
  114. REPORT_ONLY: config.get<boolean>('csp.report_only'),
  115. REPORT_URI: config.get<boolean>('csp.report_uri')
  116. },
  117. TRACKER: {
  118. ENABLED: config.get<boolean>('tracker.enabled'),
  119. PRIVATE: config.get<boolean>('tracker.private'),
  120. REJECT_TOO_MANY_ANNOUNCES: config.get<boolean>('tracker.reject_too_many_announces')
  121. },
  122. HISTORY: {
  123. VIDEOS: {
  124. MAX_AGE: parseDurationToMs(config.get('history.videos.max_age'))
  125. }
  126. },
  127. VIEWS: {
  128. VIDEOS: {
  129. REMOTE: {
  130. MAX_AGE: parseDurationToMs(config.get('views.videos.remote.max_age'))
  131. }
  132. }
  133. },
  134. PLUGINS: {
  135. INDEX: {
  136. ENABLED: config.get<boolean>('plugins.index.enabled'),
  137. CHECK_LATEST_VERSIONS_INTERVAL: parseDurationToMs(config.get<string>('plugins.index.check_latest_versions_interval')),
  138. URL: config.get<string>('plugins.index.url')
  139. }
  140. },
  141. ADMIN: {
  142. get EMAIL () { return config.get<string>('admin.email') }
  143. },
  144. CONTACT_FORM: {
  145. get ENABLED () { return config.get<boolean>('contact_form.enabled') }
  146. },
  147. SIGNUP: {
  148. get ENABLED () { return config.get<boolean>('signup.enabled') },
  149. get LIMIT () { return config.get<number>('signup.limit') },
  150. get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') },
  151. FILTERS: {
  152. CIDR: {
  153. get WHITELIST () { return config.get<string[]>('signup.filters.cidr.whitelist') },
  154. get BLACKLIST () { return config.get<string[]>('signup.filters.cidr.blacklist') }
  155. }
  156. }
  157. },
  158. USER: {
  159. get VIDEO_QUOTA () { return parseBytes(config.get<number>('user.video_quota')) },
  160. get VIDEO_QUOTA_DAILY () { return parseBytes(config.get<number>('user.video_quota_daily')) }
  161. },
  162. TRANSCODING: {
  163. get ENABLED () { return config.get<boolean>('transcoding.enabled') },
  164. get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') },
  165. get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') },
  166. get THREADS () { return config.get<number>('transcoding.threads') },
  167. RESOLUTIONS: {
  168. get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') },
  169. get '360p' () { return config.get<boolean>('transcoding.resolutions.360p') },
  170. get '480p' () { return config.get<boolean>('transcoding.resolutions.480p') },
  171. get '720p' () { return config.get<boolean>('transcoding.resolutions.720p') },
  172. get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') },
  173. get '2160p' () { return config.get<boolean>('transcoding.resolutions.2160p') }
  174. },
  175. HLS: {
  176. get ENABLED () { return config.get<boolean>('transcoding.hls.enabled') }
  177. }
  178. },
  179. IMPORT: {
  180. VIDEOS: {
  181. HTTP: {
  182. get ENABLED () { return config.get<boolean>('import.videos.http.enabled') }
  183. },
  184. TORRENT: {
  185. get ENABLED () { return config.get<boolean>('import.videos.torrent.enabled') }
  186. }
  187. }
  188. },
  189. AUTO_BLACKLIST: {
  190. VIDEOS: {
  191. OF_USERS: {
  192. get ENABLED () { return config.get<boolean>('auto_blacklist.videos.of_users.enabled') }
  193. }
  194. }
  195. },
  196. CACHE: {
  197. PREVIEWS: {
  198. get SIZE () { return config.get<number>('cache.previews.size') }
  199. },
  200. VIDEO_CAPTIONS: {
  201. get SIZE () { return config.get<number>('cache.captions.size') }
  202. }
  203. },
  204. INSTANCE: {
  205. get NAME () { return config.get<string>('instance.name') },
  206. get SHORT_DESCRIPTION () { return config.get<string>('instance.short_description') },
  207. get DESCRIPTION () { return config.get<string>('instance.description') },
  208. get TERMS () { return config.get<string>('instance.terms') },
  209. get IS_NSFW () { return config.get<boolean>('instance.is_nsfw') },
  210. get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') },
  211. get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') },
  212. CUSTOMIZATIONS: {
  213. get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') },
  214. get CSS () { return config.get<string>('instance.customizations.css') }
  215. },
  216. get ROBOTS () { return config.get<string>('instance.robots') },
  217. get SECURITYTXT () { return config.get<string>('instance.securitytxt') },
  218. get SECURITYTXT_CONTACT () { return config.get<string>('admin.email') }
  219. },
  220. SERVICES: {
  221. TWITTER: {
  222. get USERNAME () { return config.get<string>('services.twitter.username') },
  223. get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') }
  224. }
  225. },
  226. FOLLOWERS: {
  227. INSTANCE: {
  228. get ENABLED () { return config.get<boolean>('followers.instance.enabled') },
  229. get MANUAL_APPROVAL () { return config.get<boolean>('followers.instance.manual_approval') }
  230. }
  231. },
  232. THEME: {
  233. get DEFAULT () { return config.get<string>('theme.default') }
  234. }
  235. }
  236. function registerConfigChangedHandler (fun: Function) {
  237. configChangedHandlers.push(fun)
  238. }
  239. // ---------------------------------------------------------------------------
  240. export {
  241. CONFIG,
  242. registerConfigChangedHandler
  243. }
  244. // ---------------------------------------------------------------------------
  245. function getLocalConfigFilePath () {
  246. const configSources = config.util.getConfigSources()
  247. if (configSources.length === 0) throw new Error('Invalid config source.')
  248. let filename = 'local'
  249. if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
  250. if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}`
  251. return join(dirname(configSources[ 0 ].name), filename + '.json')
  252. }
  253. function buildVideosRedundancy (objs: any[]): VideosRedundancy[] {
  254. if (!objs) return []
  255. if (!Array.isArray(objs)) return objs
  256. return objs.map(obj => {
  257. return Object.assign({}, obj, {
  258. minLifetime: parseDurationToMs(obj.min_lifetime),
  259. size: bytes.parse(obj.size),
  260. minViews: obj.min_views
  261. })
  262. })
  263. }
  264. export function reloadConfig () {
  265. function directory () {
  266. if (process.env.NODE_CONFIG_DIR) {
  267. return process.env.NODE_CONFIG_DIR
  268. }
  269. return join(root(), 'config')
  270. }
  271. function purge () {
  272. for (const fileName in require.cache) {
  273. if (-1 === fileName.indexOf(directory())) {
  274. continue
  275. }
  276. delete require.cache[fileName]
  277. }
  278. delete require.cache[require.resolve('config')]
  279. }
  280. purge()
  281. config = require('config')
  282. for (const configChangedHandler of configChangedHandlers) {
  283. configChangedHandler()
  284. }
  285. }