helper.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. const fs = require('fs')
  2. const merge = require('lodash.merge')
  3. const stripIndent = require('common-tags/lib/stripIndent')
  4. const utils = require('../server/helpers/utils')
  5. const logger = require('../server/logger')
  6. const crypto = require('crypto')
  7. // @ts-ignore
  8. const { version } = require('../../package.json')
  9. /**
  10. * Reads all companion configuration set via environment variables
  11. * and via the config file path
  12. *
  13. * @returns {object}
  14. */
  15. exports.getCompanionOptions = () => {
  16. return merge({}, getConfigFromEnv(), getConfigFromFile())
  17. }
  18. /**
  19. * Loads the config from environment variables
  20. *
  21. * @returns {object}
  22. */
  23. const getConfigFromEnv = () => {
  24. const uploadUrls = process.env.COMPANION_UPLOAD_URLS
  25. const domains = process.env.COMPANION_DOMAINS || process.env.COMPANION_DOMAIN || null
  26. const validHosts = domains ? domains.split(',') : []
  27. return {
  28. providerOptions: {
  29. drive: {
  30. key: process.env.COMPANION_GOOGLE_KEY,
  31. secret: getSecret('COMPANION_GOOGLE_SECRET')
  32. },
  33. dropbox: {
  34. key: process.env.COMPANION_DROPBOX_KEY,
  35. secret: getSecret('COMPANION_DROPBOX_SECRET')
  36. },
  37. instagram: {
  38. key: process.env.COMPANION_INSTAGRAM_KEY,
  39. secret: getSecret('COMPANION_INSTAGRAM_SECRET')
  40. },
  41. facebook: {
  42. key: process.env.COMPANION_FACEBOOK_KEY,
  43. secret: getSecret('COMPANION_FACEBOOK_SECRET')
  44. },
  45. onedrive: {
  46. key: process.env.COMPANION_ONEDRIVE_KEY,
  47. secret: getSecret('COMPANION_ONEDRIVE_SECRET')
  48. },
  49. zoom: {
  50. key: process.env.COMPANION_ZOOM_KEY,
  51. secret: getSecret('COMPANION_ZOOM_SECRET'),
  52. verificationToken: getSecret('COMPANION_ZOOM_VERIFICATION_TOKEN')
  53. },
  54. s3: {
  55. key: process.env.COMPANION_AWS_KEY,
  56. secret: getSecret('COMPANION_AWS_SECRET'),
  57. bucket: process.env.COMPANION_AWS_BUCKET,
  58. endpoint: process.env.COMPANION_AWS_ENDPOINT,
  59. region: process.env.COMPANION_AWS_REGION,
  60. useAccelerateEndpoint:
  61. process.env.COMPANION_AWS_USE_ACCELERATE_ENDPOINT === 'true',
  62. expires: parseInt(process.env.COMPANION_AWS_EXPIRES || '300', 10),
  63. acl: process.env.COMPANION_AWS_ACL || 'public-read'
  64. }
  65. },
  66. server: {
  67. host: process.env.COMPANION_DOMAIN,
  68. protocol: process.env.COMPANION_PROTOCOL,
  69. path: process.env.COMPANION_PATH,
  70. implicitPath: process.env.COMPANION_IMPLICIT_PATH,
  71. oauthDomain: process.env.COMPANION_OAUTH_DOMAIN,
  72. validHosts: validHosts
  73. },
  74. filePath: process.env.COMPANION_DATADIR,
  75. redisUrl: process.env.COMPANION_REDIS_URL,
  76. // adding redisOptions to keep all companion options easily visible
  77. // redisOptions refers to https://www.npmjs.com/package/redis#options-object-properties
  78. redisOptions: {},
  79. sendSelfEndpoint: process.env.COMPANION_SELF_ENDPOINT,
  80. uploadUrls: uploadUrls ? uploadUrls.split(',') : null,
  81. secret: getSecret('COMPANION_SECRET') || generateSecret(),
  82. debug: process.env.NODE_ENV && process.env.NODE_ENV !== 'production',
  83. // TODO: this is a temporary hack to support distributed systems.
  84. // it is not documented, because it should be changed soon.
  85. cookieDomain: process.env.COMPANION_COOKIE_DOMAIN,
  86. multipleInstances: true
  87. }
  88. }
  89. /**
  90. * Tries to read the secret from a file if the according environment variable is set.
  91. * Otherwise it falls back to the standard secret environment variable.
  92. *
  93. * @param {string} baseEnvVar
  94. *
  95. * @returns {string}
  96. */
  97. const getSecret = (baseEnvVar) => {
  98. const secretFile = process.env[`${baseEnvVar}_FILE`]
  99. return secretFile
  100. ? fs.readFileSync(secretFile).toString()
  101. : process.env[baseEnvVar]
  102. }
  103. /**
  104. * Auto-generates server secret
  105. *
  106. * @returns {string}
  107. */
  108. const generateSecret = () => {
  109. logger.warn('auto-generating server secret because none was specified', 'startup.secret')
  110. return crypto.randomBytes(64).toString('hex')
  111. }
  112. /**
  113. * Loads the config from a file and returns it as an object
  114. *
  115. * @returns {object}
  116. */
  117. const getConfigFromFile = () => {
  118. const path = getConfigPath()
  119. if (!path) return {}
  120. const rawdata = fs.readFileSync(getConfigPath())
  121. // @ts-ignore
  122. return JSON.parse(rawdata)
  123. }
  124. /**
  125. * Returns the config path specified via cli arguments
  126. *
  127. * @returns {string}
  128. */
  129. const getConfigPath = () => {
  130. let configPath
  131. for (let i = process.argv.length - 1; i >= 0; i--) {
  132. const isConfigFlag = process.argv[i] === '-c' || process.argv[i] === '--config'
  133. const flagHasValue = i + 1 <= process.argv.length
  134. if (isConfigFlag && flagHasValue) {
  135. configPath = process.argv[i + 1]
  136. break
  137. }
  138. }
  139. return configPath
  140. }
  141. /**
  142. *
  143. * @param {string} url
  144. */
  145. exports.hasProtocol = (url) => {
  146. return url.startsWith('http://') || url.startsWith('https://')
  147. }
  148. exports.buildHelpfulStartupMessage = (companionOptions) => {
  149. const buildURL = utils.getURLBuilder(companionOptions)
  150. const callbackURLs = []
  151. Object.keys(companionOptions.providerOptions).forEach((providerName) => {
  152. // s3 does not need redirect_uris
  153. if (providerName === 's3') {
  154. return
  155. }
  156. callbackURLs.push(buildURL(`/connect/${providerName}/callback`, true))
  157. })
  158. return stripIndent`
  159. Welcome to Companion v${version}
  160. ===================================
  161. Congratulations on setting up Companion! Thanks for joining our cause, you have taken
  162. the first step towards the future of file uploading! We
  163. hope you are as excited about this as we are!
  164. While you did an awesome job on getting Companion running, this is just the welcome
  165. message, so let's talk about the places that really matter:
  166. - Be sure to add ${callbackURLs.join(', ')} as your Oauth redirect uris on their corresponding developer interfaces.
  167. - The URL ${buildURL('/metrics', true)} is available for statistics to keep Companion running smoothly
  168. - https://github.com/transloadit/uppy/issues - report your bugs here
  169. So quit lollygagging, start uploading and experience the future!
  170. `
  171. }