forked from transloadit/uppy
/
companion.js
116 lines (100 loc) · 3.47 KB
/
companion.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
const ms = require('ms')
const fs = require('node:fs')
const { isURL } = require('validator')
const logger = require('../server/logger')
const defaultOptions = {
server: {
protocol: 'http',
path: '',
},
providerOptions: {},
s3: {
endpoint: 'https://{service}.{region}.amazonaws.com',
conditions: [],
useAccelerateEndpoint: false,
getKey: (req, filename) => filename,
expires: ms('5 minutes') / 1000,
},
allowLocalUrls: false,
logClientVersion: true,
periodicPingUrls: [],
streamingUpload: false,
clientSocketConnectTimeout: 60000,
metrics: true,
}
/**
* @param {object} companionOptions
*/
function getMaskableSecrets (companionOptions) {
const secrets = []
const { providerOptions, customProviders, s3 } = companionOptions
Object.keys(providerOptions).forEach((provider) => {
if (providerOptions[provider].secret) {
secrets.push(providerOptions[provider].secret)
}
})
if (customProviders) {
Object.keys(customProviders).forEach((provider) => {
if (customProviders[provider].config && customProviders[provider].config.secret) {
secrets.push(customProviders[provider].config.secret)
}
})
}
if (s3?.secret) {
secrets.push(s3.secret)
}
return secrets
}
/**
* validates that the mandatory companion options are set.
* If it is invalid, it will console an error of unset options and exits the process.
* If it is valid, nothing happens.
*
* @param {object} companionOptions
*/
const validateConfig = (companionOptions) => {
const mandatoryOptions = ['secret', 'filePath', 'server.host']
/** @type {string[]} */
const unspecified = []
mandatoryOptions.forEach((i) => {
const value = i.split('.').reduce((prev, curr) => (prev ? prev[curr] : undefined), companionOptions)
if (!value) unspecified.push(`"${i}"`)
})
// vaidate that all required config is specified
if (unspecified.length) {
const messagePrefix = 'Please specify the following options to use companion:'
throw new Error(`${messagePrefix}\n${unspecified.join(',\n')}`)
}
// validate that specified filePath is writeable/readable.
try {
// @ts-ignore
fs.accessSync(`${companionOptions.filePath}`, fs.R_OK | fs.W_OK) // eslint-disable-line no-bitwise
} catch (err) {
throw new Error(
`No access to "${companionOptions.filePath}". Please ensure the directory exists and with read/write permissions.`,
)
}
const { providerOptions, periodicPingUrls } = companionOptions
if (providerOptions) {
const deprecatedOptions = { microsoft: 'providerOptions.onedrive', google: 'providerOptions.drive', s3: 's3' }
Object.keys(deprecatedOptions).forEach((deprecated) => {
if (Object.prototype.hasOwnProperty.call(providerOptions, deprecated)) {
throw new Error(`The Provider option "providerOptions.${deprecated}" is no longer supported. Please use the option "${deprecatedOptions[deprecated]}" instead.`)
}
})
}
if (companionOptions.uploadUrls == null || companionOptions.uploadUrls.length === 0) {
logger.warn('Running without uploadUrls specified is a security risk if running in production', 'startup.uploadUrls')
}
if (periodicPingUrls != null && (
!Array.isArray(periodicPingUrls)
|| periodicPingUrls.some((url2) => !isURL(url2, { protocols: ['http', 'https'], require_protocol: true, require_tld: false }))
)) {
throw new TypeError('Invalid periodicPingUrls')
}
}
module.exports = {
defaultOptions,
getMaskableSecrets,
validateConfig,
}