config.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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. OBJECT: {
  49. PREFIX: config.get<string>('email.object.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. ADMIN: {
  135. get EMAIL () { return config.get<string>('admin.email') }
  136. },
  137. CONTACT_FORM: {
  138. get ENABLED () { return config.get<boolean>('contact_form.enabled') }
  139. },
  140. SIGNUP: {
  141. get ENABLED () { return config.get<boolean>('signup.enabled') },
  142. get LIMIT () { return config.get<number>('signup.limit') },
  143. get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') },
  144. FILTERS: {
  145. CIDR: {
  146. get WHITELIST () { return config.get<string[]>('signup.filters.cidr.whitelist') },
  147. get BLACKLIST () { return config.get<string[]>('signup.filters.cidr.blacklist') }
  148. }
  149. }
  150. },
  151. USER: {
  152. get VIDEO_QUOTA () { return parseBytes(config.get<number>('user.video_quota')) },
  153. get VIDEO_QUOTA_DAILY () { return parseBytes(config.get<number>('user.video_quota_daily')) }
  154. },
  155. TRANSCODING: {
  156. get ENABLED () { return config.get<boolean>('transcoding.enabled') },
  157. get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') },
  158. get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') },
  159. get THREADS () { return config.get<number>('transcoding.threads') },
  160. RESOLUTIONS: {
  161. get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') },
  162. get '360p' () { return config.get<boolean>('transcoding.resolutions.360p') },
  163. get '480p' () { return config.get<boolean>('transcoding.resolutions.480p') },
  164. get '720p' () { return config.get<boolean>('transcoding.resolutions.720p') },
  165. get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') },
  166. get '2160p' () { return config.get<boolean>('transcoding.resolutions.2160p') }
  167. },
  168. HLS: {
  169. get ENABLED () { return config.get<boolean>('transcoding.hls.enabled') }
  170. }
  171. },
  172. IMPORT: {
  173. VIDEOS: {
  174. HTTP: {
  175. get ENABLED () { return config.get<boolean>('import.videos.http.enabled') }
  176. },
  177. TORRENT: {
  178. get ENABLED () { return config.get<boolean>('import.videos.torrent.enabled') }
  179. }
  180. }
  181. },
  182. AUTO_BLACKLIST: {
  183. VIDEOS: {
  184. OF_USERS: {
  185. get ENABLED () { return config.get<boolean>('auto_blacklist.videos.of_users.enabled') }
  186. }
  187. }
  188. },
  189. CACHE: {
  190. PREVIEWS: {
  191. get SIZE () { return config.get<number>('cache.previews.size') }
  192. },
  193. VIDEO_CAPTIONS: {
  194. get SIZE () { return config.get<number>('cache.captions.size') }
  195. }
  196. },
  197. INSTANCE: {
  198. get NAME () { return config.get<string>('instance.name') },
  199. get SHORT_DESCRIPTION () { return config.get<string>('instance.short_description') },
  200. get DESCRIPTION () { return config.get<string>('instance.description') },
  201. get TERMS () { return config.get<string>('instance.terms') },
  202. get IS_NSFW () { return config.get<boolean>('instance.is_nsfw') },
  203. get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') },
  204. get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') },
  205. CUSTOMIZATIONS: {
  206. get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') },
  207. get CSS () { return config.get<string>('instance.customizations.css') }
  208. },
  209. get ROBOTS () { return config.get<string>('instance.robots') },
  210. get SECURITYTXT () { return config.get<string>('instance.securitytxt') },
  211. get SECURITYTXT_CONTACT () { return config.get<string>('admin.email') }
  212. },
  213. SERVICES: {
  214. TWITTER: {
  215. get USERNAME () { return config.get<string>('services.twitter.username') },
  216. get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') }
  217. }
  218. },
  219. FOLLOWERS: {
  220. INSTANCE: {
  221. get ENABLED () { return config.get<boolean>('followers.instance.enabled') },
  222. get MANUAL_APPROVAL () { return config.get<boolean>('followers.instance.manual_approval') }
  223. }
  224. }
  225. }
  226. function registerConfigChangedHandler (fun: Function) {
  227. configChangedHandlers.push(fun)
  228. }
  229. // ---------------------------------------------------------------------------
  230. export {
  231. CONFIG,
  232. registerConfigChangedHandler
  233. }
  234. // ---------------------------------------------------------------------------
  235. function getLocalConfigFilePath () {
  236. const configSources = config.util.getConfigSources()
  237. if (configSources.length === 0) throw new Error('Invalid config source.')
  238. let filename = 'local'
  239. if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
  240. if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}`
  241. return join(dirname(configSources[ 0 ].name), filename + '.json')
  242. }
  243. function buildVideosRedundancy (objs: any[]): VideosRedundancy[] {
  244. if (!objs) return []
  245. if (!Array.isArray(objs)) return objs
  246. return objs.map(obj => {
  247. return Object.assign({}, obj, {
  248. minLifetime: parseDurationToMs(obj.min_lifetime),
  249. size: bytes.parse(obj.size),
  250. minViews: obj.min_views
  251. })
  252. })
  253. }
  254. export function reloadConfig () {
  255. function directory () {
  256. if (process.env.NODE_CONFIG_DIR) {
  257. return process.env.NODE_CONFIG_DIR
  258. }
  259. return join(root(), 'config')
  260. }
  261. function purge () {
  262. for (const fileName in require.cache) {
  263. if (-1 === fileName.indexOf(directory())) {
  264. continue
  265. }
  266. delete require.cache[fileName]
  267. }
  268. delete require.cache[require.resolve('config')]
  269. }
  270. purge()
  271. config = require('config')
  272. for (const configChangedHandler of configChangedHandlers) {
  273. configChangedHandler()
  274. }
  275. }