2017-10-25 09:49:37 -04:00
2017-04-12 13:57:55 -04:00
'use strict'
2018-03-25 18:30:17 -04:00
const crypto = require ( 'crypto' )
2017-04-12 13:57:55 -04:00
const fs = require ( 'fs' )
const path = require ( 'path' )
2019-05-30 18:27:56 -04:00
const { merge } = require ( 'lodash' )
2017-04-12 13:57:55 -04:00
const deepFreeze = require ( 'deep-freeze' )
2019-05-30 18:27:56 -04:00
const { Environment , Permission } = require ( './enum' )
2018-03-17 21:14:50 -04:00
const logger = require ( '../logger' )
2019-05-30 18:27:56 -04:00
const { getGitCommit , getGitHubURL } = require ( './utils' )
2017-04-12 13:57:55 -04:00
2018-09-10 16:35:38 -04:00
const appRootPath = path . resolve ( _ _dirname , '../../' )
2017-04-12 13:57:55 -04:00
const env = process . env . NODE _ENV || Environment . development
const debugConfig = {
debug : ( env === Environment . development )
}
2018-01-26 08:00:48 -05:00
// Get version string from package.json
2019-05-30 18:27:56 -04:00
const { version , repository } = require ( path . join ( appRootPath , 'package.json' ) )
2018-10-05 13:33:40 -04:00
const commitID = getGitCommit ( appRootPath )
const sourceURL = getGitHubURL ( repository . url , commitID || version )
const fullversion = commitID ? ` ${ version } - ${ commitID } ` : version
2018-01-19 07:23:30 -05:00
2017-04-12 13:57:55 -04:00
const packageConfig = {
2018-01-19 07:23:30 -05:00
version : version ,
2018-10-05 13:33:40 -04:00
minimumCompatibleVersion : '0.5.0' ,
fullversion : fullversion ,
sourceURL : sourceURL
2017-04-12 13:57:55 -04:00
}
2018-09-05 13:50:46 -04:00
const configFilePath = path . resolve ( appRootPath , process . env . CMD _CONFIG _FILE ||
'config.json' )
2017-04-12 13:57:55 -04:00
const fileConfig = fs . existsSync ( configFilePath ) ? require ( configFilePath ) [ env ] : undefined
let config = require ( './default' )
merge ( config , require ( './defaultSSL' ) )
2018-03-07 09:17:35 -05:00
merge ( config , require ( './oldDefault' ) )
2017-04-12 13:57:55 -04:00
merge ( config , debugConfig )
merge ( config , packageConfig )
merge ( config , fileConfig )
merge ( config , require ( './oldEnvironment' ) )
2018-06-24 07:22:51 -04:00
merge ( config , require ( './hackmdEnvironment' ) )
2017-04-12 13:57:55 -04:00
merge ( config , require ( './environment' ) )
merge ( config , require ( './dockerSecret' ) )
2018-11-13 17:29:33 -05:00
if ( [ 'debug' , 'verbose' , 'info' , 'warn' , 'error' ] . includes ( config . loglevel ) ) {
logger . level = config . loglevel
} else {
logger . error ( 'Selected loglevel %s doesn\'t exist, using default level \'debug\'. Available options: debug, verbose, info, warn, error' , config . loglevel )
}
2020-08-26 20:04:49 -04:00
if ( ! [ 'strict' , 'lax' , 'none' ] . includes ( config . cookiePolicy ) ) {
2020-09-08 03:58:15 -04:00
logger . error ( 'Cookie SameSite policy %s does not exist. Falling back to lax. Available values are: strict, lax, none.' , config . cookiePolicy )
2020-08-27 03:05:17 -04:00
config . cookiePolicy = 'lax'
2020-08-26 20:04:49 -04:00
}
2017-04-12 13:57:55 -04:00
// load LDAP CA
if ( config . ldap . tlsca ) {
2021-02-15 03:42:51 -05:00
const ca = config . ldap . tlsca . split ( ',' )
const caContent = [ ]
for ( const i of ca ) {
2017-06-01 06:58:55 -04:00
if ( fs . existsSync ( i ) ) {
caContent . push ( fs . readFileSync ( i , 'utf8' ) )
2017-04-12 13:57:55 -04:00
}
}
2021-02-15 03:42:51 -05:00
const tlsOptions = {
2017-04-12 13:57:55 -04:00
ca : caContent
}
config . ldap . tlsOptions = config . ldap . tlsOptions ? Object . assign ( config . ldap . tlsOptions , tlsOptions ) : tlsOptions
}
// Permission
config . permission = Permission
2018-04-10 08:38:39 -04:00
if ( ! config . allowAnonymous && ! config . allowAnonymousEdits ) {
2017-04-12 13:57:55 -04:00
delete config . permission . freely
}
2018-03-07 09:17:35 -05:00
if ( ! ( config . defaultPermission in config . permission ) ) {
config . defaultPermission = config . permission . editable
2017-04-12 13:57:55 -04:00
}
// cache result, cannot change config in runtime!!!
config . isStandardHTTPsPort = ( function isStandardHTTPsPort ( ) {
2018-03-07 09:17:35 -05:00
return config . useSSL && config . port === 443
2017-04-12 13:57:55 -04:00
} ) ( )
config . isStandardHTTPPort = ( function isStandardHTTPPort ( ) {
2018-03-07 09:17:35 -05:00
return ! config . useSSL && config . port === 80
2017-04-12 13:57:55 -04:00
} ) ( )
// cache serverURL
2018-03-07 09:17:35 -05:00
config . serverURL = ( function getserverurl ( ) {
2021-02-15 03:42:51 -05:00
let url = ''
2017-04-12 13:57:55 -04:00
if ( config . domain ) {
2021-02-15 03:42:51 -05:00
const protocol = config . protocolUseSSL ? 'https://' : 'http://'
2017-04-12 13:57:55 -04:00
url = protocol + config . domain
2018-03-07 09:17:35 -05:00
if ( config . urlAddPort ) {
2017-04-12 13:57:55 -04:00
if ( ! config . isStandardHTTPPort || ! config . isStandardHTTPsPort ) {
url += ':' + config . port
}
}
}
2018-03-07 09:17:35 -05:00
if ( config . urlPath ) {
url += '/' + config . urlPath
2017-04-12 13:57:55 -04:00
}
return url
} ) ( )
2018-11-28 08:38:42 -05:00
if ( config . serverURL === '' ) {
logger . warn ( 'Neither \'domain\' nor \'CMD_DOMAIN\' is configured. This can cause issues with various components.\nHint: Make sure \'protocolUseSSL\' and \'urlAddPort\' or \'CMD_PROTOCOL_USESSL\' and \'CMD_URL_ADDPORT\' are configured properly.' )
}
2017-04-12 13:57:55 -04:00
config . Environment = Environment
// auth method
config . isFacebookEnable = config . facebook . clientID && config . facebook . clientSecret
config . isGoogleEnable = config . google . clientID && config . google . clientSecret
config . isDropboxEnable = config . dropbox . clientID && config . dropbox . clientSecret
config . isTwitterEnable = config . twitter . consumerKey && config . twitter . consumerSecret
config . isEmailEnable = config . email
2017-08-31 17:33:55 -04:00
config . isOpenIDEnable = config . openID
2017-04-12 13:57:55 -04:00
config . isGitHubEnable = config . github . clientID && config . github . clientSecret
config . isGitLabEnable = config . gitlab . clientID && config . gitlab . clientSecret
2017-10-29 06:16:40 -04:00
config . isMattermostEnable = config . mattermost . clientID && config . mattermost . clientSecret
2017-04-12 13:57:55 -04:00
config . isLDAPEnable = config . ldap . url
2017-11-27 22:46:58 -05:00
config . isSAMLEnable = config . saml . idpSsoUrl
2017-06-27 13:08:05 -04:00
config . isOAuth2Enable = config . oauth2 . clientID && config . oauth2 . clientSecret
2017-04-12 13:57:55 -04:00
2018-07-30 09:47:09 -04:00
// Check gitlab api version
2018-09-24 18:26:30 -04:00
if ( config . gitlab && config . gitlab . version !== 'v4' && config . gitlab . version !== 'v3' ) {
2020-11-26 15:11:24 -05:00
logger . warn ( 'config.json contains wrong version (' + config . gitlab . version + ') for gitlab api; it should be \'v3\' or \'v4\'. Defaulting to v4' )
2018-07-30 09:47:09 -04:00
config . gitlab . version = 'v4'
}
2018-11-07 07:12:50 -05:00
// If gitlab scope is api, enable snippets Export/import
2019-01-25 13:48:31 -05:00
config . isGitlabSnippetsEnable = ( ! config . gitlab . scope || config . gitlab . scope === 'api' ) && config . isGitLabEnable
2018-07-30 09:47:09 -04:00
2018-06-04 19:29:27 -04:00
// Only update i18n files in development setups
config . updateI18nFiles = ( env === Environment . development )
2018-01-26 08:00:48 -05:00
// merge legacy values
2021-02-15 03:42:51 -05:00
const keys = Object . keys ( config )
2018-03-07 09:17:35 -05:00
const uppercase = /[A-Z]/
for ( let i = keys . length ; i -- ; ) {
2021-02-15 03:42:51 -05:00
const lowercaseKey = keys [ i ] . toLowerCase ( )
2018-03-07 09:17:35 -05:00
// if the config contains uppercase letters
// and a lowercase version of this setting exists
// and the config with uppercase is not set
// we set the new config using the old key.
if ( uppercase . test ( keys [ i ] ) &&
2018-03-26 14:49:24 -04:00
config [ lowercaseKey ] !== undefined &&
fileConfig [ keys [ i ] ] === undefined ) {
2020-11-26 15:11:24 -05:00
logger . warn ( 'config.json contains deprecated lowercase setting for ' + keys [ i ] + '. Please change your config.json file to replace ' + lowercaseKey + ' with ' + keys [ i ] )
2018-03-07 09:17:35 -05:00
config [ keys [ i ] ] = config [ lowercaseKey ]
}
2018-01-26 08:00:48 -05:00
}
2018-06-24 07:22:51 -04:00
// Notify users about the prefix change and inform them they use legacy prefix for environment variables
if ( Object . keys ( process . env ) . toString ( ) . indexOf ( 'HMD_' ) !== - 1 ) {
2020-11-15 14:12:22 -05:00
logger . warn ( 'Using legacy HMD prefix for environment variables. Please change your variables in future. For details see: https://github.com/hedgedoc/hedgedoc/blob/master/docs/configuration.md' )
2018-06-24 07:22:51 -04:00
}
2018-03-25 18:30:17 -04:00
// Generate session secret if it stays on default values
if ( config . sessionSecret === 'secret' ) {
2020-11-26 15:11:24 -05:00
logger . warn ( 'Session secret not set. Using random generated one. Please set `sessionSecret` in your config.json file. All users will be logged out.' )
2018-03-25 18:30:17 -04:00
config . sessionSecret = crypto . randomBytes ( Math . ceil ( config . sessionSecretLen / 2 ) ) // generate crypto graphic random number
2019-05-30 18:27:56 -04:00
. toString ( 'hex' ) // convert to hexadecimal format
. slice ( 0 , config . sessionSecretLen ) // return required number of characters
2018-03-25 18:30:17 -04:00
}
2018-03-17 21:14:50 -04:00
// Validate upload upload providers
2019-02-01 06:33:27 -05:00
if ( [ 'filesystem' , 's3' , 'minio' , 'imgur' , 'azure' , 'lutim' ] . indexOf ( config . imageUploadType ) === - 1 ) {
logger . error ( '"imageuploadtype" is not correctly set. Please use "filesystem", "s3", "minio", "azure", "lutim" or "imgur". Defaulting to "filesystem"' )
2018-07-09 14:27:15 -04:00
config . imageUploadType = 'filesystem'
2018-03-17 21:14:50 -04:00
}
2018-01-20 09:08:31 -05:00
// figure out mime types for image uploads
2018-03-07 09:17:35 -05:00
switch ( config . imageUploadType ) {
2018-01-20 09:08:31 -05:00
case 'imgur' :
config . allowedUploadMimeTypes = [
'image/jpeg' ,
'image/png' ,
'image/gif'
]
break
default :
config . allowedUploadMimeTypes = [
'image/jpeg' ,
'image/png' ,
'image/gif' ,
'image/svg+xml'
]
}
2017-04-12 13:57:55 -04:00
// generate correct path
2018-03-07 09:17:35 -05:00
config . sslCAPath . forEach ( function ( capath , i , array ) {
2017-12-22 06:25:13 -05:00
array [ i ] = path . resolve ( appRootPath , capath )
2017-12-22 06:19:19 -05:00
} )
2017-11-28 08:23:50 -05:00
2018-09-05 13:56:41 -04:00
config . sslCertPath = path . resolve ( appRootPath , config . sslCertPath )
config . sslKeyPath = path . resolve ( appRootPath , config . sslKeyPath )
config . dhParamPath = path . resolve ( appRootPath , config . dhParamPath )
2018-09-10 16:35:38 -04:00
config . viewPath = path . resolve ( appRootPath , config . viewPath )
2018-09-05 13:56:41 -04:00
config . tmpPath = path . resolve ( appRootPath , config . tmpPath )
config . defaultNotePath = path . resolve ( appRootPath , config . defaultNotePath )
config . docsPath = path . resolve ( appRootPath , config . docsPath )
config . uploadsPath = path . resolve ( appRootPath , config . uploadsPath )
2017-04-12 13:57:55 -04:00
2017-10-25 09:49:37 -04:00
// make config readonly
2017-04-12 13:57:55 -04:00
config = deepFreeze ( config )
module . exports = config