Migrate config/index.js to TypeScript

Signed-off-by: David Mehren <dmehren1@gmail.com>
This commit is contained in:
David Mehren 2020-04-12 13:09:31 +02:00
parent 637833ab18
commit dd11483f44
No known key found for this signature in database
GPG key ID: 6017AF117F9756CB
2 changed files with 204 additions and 209 deletions

View file

@ -1,209 +0,0 @@
'use strict'
const crypto = require('crypto')
const fs = require('fs')
const path = require('path')
const { merge } = require('lodash')
const deepFreeze = require('deep-freeze')
const { Environment, Permission } = require('./enum')
const logger = require('../logger')
const { getGitCommit, getGitHubURL } = require('./utils')
const appRootPath = path.resolve(__dirname, '../../')
const env = process.env.NODE_ENV || Environment.development
const debugConfig = {
debug: (env === Environment.development)
}
// Get version string from package.json
const { version, repository } = require(path.join(appRootPath, 'package.json'))
const commitID = getGitCommit(appRootPath)
const sourceURL = getGitHubURL(repository.url, commitID || version)
const fullversion = commitID ? `${version}-${commitID}` : version
const packageConfig = {
version: version,
minimumCompatibleVersion: '0.5.0',
fullversion: fullversion,
sourceURL: sourceURL
}
const configFilePath = path.resolve(appRootPath, process.env.CMD_CONFIG_FILE ||
'config.json')
const fileConfig = fs.existsSync(configFilePath) ? require(configFilePath)[env] : undefined
let config = require('./default')
merge(config, require('./defaultSSL'))
merge(config, require('./oldDefault'))
merge(config, debugConfig)
merge(config, packageConfig)
merge(config, fileConfig)
merge(config, require('./oldEnvironment'))
merge(config, require('./hackmdEnvironment'))
merge(config, require('./environment'))
merge(config, require('./dockerSecret'))
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)
}
// load LDAP CA
if (config.ldap.tlsca) {
let ca = config.ldap.tlsca.split(',')
let caContent = []
for (let i of ca) {
if (fs.existsSync(i)) {
caContent.push(fs.readFileSync(i, 'utf8'))
}
}
let tlsOptions = {
ca: caContent
}
config.ldap.tlsOptions = config.ldap.tlsOptions ? Object.assign(config.ldap.tlsOptions, tlsOptions) : tlsOptions
}
// Permission
config.permission = Permission
if (!config.allowAnonymous && !config.allowAnonymousEdits) {
delete config.permission.freely
}
if (!(config.defaultPermission in config.permission)) {
config.defaultPermission = config.permission.editable
}
// cache result, cannot change config in runtime!!!
config.isStandardHTTPsPort = (function isStandardHTTPsPort () {
return config.useSSL && config.port === 443
})()
config.isStandardHTTPPort = (function isStandardHTTPPort () {
return !config.useSSL && config.port === 80
})()
// cache serverURL
config.serverURL = (function getserverurl () {
var url = ''
if (config.domain) {
var protocol = config.protocolUseSSL ? 'https://' : 'http://'
url = protocol + config.domain
if (config.urlAddPort) {
if (!config.isStandardHTTPPort || !config.isStandardHTTPsPort) {
url += ':' + config.port
}
}
}
if (config.urlPath) {
url += '/' + config.urlPath
}
return url
})()
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.')
}
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
config.isOpenIDEnable = config.openID
config.isGitHubEnable = config.github.clientID && config.github.clientSecret
config.isGitLabEnable = config.gitlab.clientID && config.gitlab.clientSecret
config.isLDAPEnable = config.ldap.url
config.isSAMLEnable = config.saml.idpSsoUrl
config.isOAuth2Enable = config.oauth2.clientID && config.oauth2.clientSecret
// Check gitlab api version
if (config.gitlab && config.gitlab.version !== 'v4' && config.gitlab.version !== 'v3') {
logger.warn('config.js contains wrong version (' + config.gitlab.version + ') for gitlab api; it should be \'v3\' or \'v4\'. Defaulting to v4')
config.gitlab.version = 'v4'
}
// If gitlab scope is api, enable snippets Export/import
config.isGitlabSnippetsEnable = (!config.gitlab.scope || config.gitlab.scope === 'api') && config.isGitLabEnable
// Only update i18n files in development setups
config.updateI18nFiles = (env === Environment.development)
// merge legacy values
let keys = Object.keys(config)
const uppercase = /[A-Z]/
for (let i = keys.length; i--;) {
let lowercaseKey = keys[i].toLowerCase()
// 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]) &&
config[lowercaseKey] !== undefined &&
fileConfig[keys[i]] === undefined) {
logger.warn('config.js contains deprecated lowercase setting for ' + keys[i] + '. Please change your config.js file to replace ' + lowercaseKey + ' with ' + keys[i])
config[keys[i]] = config[lowercaseKey]
}
}
// 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) {
logger.warn('Using legacy HMD prefix for environment variables. Please change your variables in future. For details see: https://github.com/codimd/server#environment-variables-will-overwrite-other-server-configs')
}
// Generate session secret if it stays on default values
if (config.sessionSecret === 'secret') {
logger.warn('Session secret not set. Using random generated one. Please set `sessionSecret` in your config.js file. All users will be logged out.')
config.sessionSecret = crypto.randomBytes(Math.ceil(config.sessionSecretLen / 2)) // generate crypto graphic random number
.toString('hex') // convert to hexadecimal format
.slice(0, config.sessionSecretLen) // return required number of characters
}
// Validate upload upload providers
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"')
config.imageUploadType = 'filesystem'
}
// figure out mime types for image uploads
switch (config.imageUploadType) {
case 'imgur':
config.allowedUploadMimeTypes = [
'image/jpeg',
'image/png',
'image/jpg',
'image/gif'
]
break
default:
config.allowedUploadMimeTypes = [
'image/jpeg',
'image/png',
'image/jpg',
'image/gif',
'image/svg+xml'
]
}
// generate correct path
config.sslCAPath.forEach(function (capath, i, array) {
array[i] = path.resolve(appRootPath, capath)
})
config.sslCertPath = path.resolve(appRootPath, config.sslCertPath)
config.sslKeyPath = path.resolve(appRootPath, config.sslKeyPath)
config.dhParamPath = path.resolve(appRootPath, config.dhParamPath)
config.viewPath = path.resolve(appRootPath, config.viewPath)
config.tmpPath = path.resolve(appRootPath, config.tmpPath)
config.publicPath = path.resolve(appRootPath, config.publicPath)
config.defaultNotePath = path.resolve(appRootPath, config.defaultNotePath)
config.docsPath = path.resolve(appRootPath, config.docsPath)
config.uploadsPath = path.resolve(appRootPath, config.uploadsPath)
config.localesPath = path.resolve(appRootPath, config.localesPath)
// make config readonly
config = deepFreeze(config)
module.exports = config

204
lib/config/index.ts Normal file
View file

@ -0,0 +1,204 @@
import crypto from 'crypto'
import fs from 'fs'
import path from 'path'
import { merge } from 'lodash'
import deepFreeze = require('deep-freeze')
import { Environment, Permission } from './enum'
import { logger } from '../logger'
import { getGitCommit, getGitHubURL } from './utils'
const appRootPath = path.resolve(__dirname, '../../')
const env = process.env.NODE_ENV || Environment.development
const debugConfig = {
debug: (env === Environment.development)
}
// Get version string from package.json
const { version, repository } = require(path.join(appRootPath, 'package.json'))
const commitID = getGitCommit(appRootPath)
const sourceURL = getGitHubURL(repository.url, commitID || version)
const fullversion = commitID ? `${version}-${commitID}` : version
const packageConfig = {
version: version,
minimumCompatibleVersion: '0.5.0',
fullversion: fullversion,
sourceURL: sourceURL
}
const configFilePath = path.resolve(appRootPath, process.env.CMD_CONFIG_FILE ||
'config.json')
const fileConfig = fs.existsSync(configFilePath) ? require(configFilePath)[env] : undefined
let defaultConfig = require('./default')
merge(defaultConfig, require('./defaultSSL'))
merge(defaultConfig, require('./oldDefault'))
merge(defaultConfig, debugConfig)
merge(defaultConfig, packageConfig)
merge(defaultConfig, fileConfig)
merge(defaultConfig, require('./oldEnvironment'))
merge(defaultConfig, require('./hackmdEnvironment'))
merge(defaultConfig, require('./environment'))
merge(defaultConfig, require('./dockerSecret'))
if (['debug', 'verbose', 'info', 'warn', 'error'].includes(defaultConfig.loglevel)) {
logger.level = defaultConfig.loglevel
} else {
logger.error('Selected loglevel %s doesn\'t exist, using default level \'debug\'. Available options: debug, verbose, info, warn, error', defaultConfig.loglevel)
}
// load LDAP CA
if (defaultConfig.ldap.tlsca) {
let ca = defaultConfig.ldap.tlsca.split(',')
let caContent: string[] = []
for (let i of ca) {
if (fs.existsSync(i)) {
caContent.push(fs.readFileSync(i, 'utf8'))
}
}
let tlsOptions = {
ca: caContent
}
defaultConfig.ldap.tlsOptions = defaultConfig.ldap.tlsOptions ? Object.assign(defaultConfig.ldap.tlsOptions, tlsOptions) : tlsOptions
}
// Permission
defaultConfig.permission = Permission
if (!defaultConfig.allowAnonymous && !defaultConfig.allowAnonymousEdits) {
delete defaultConfig.permission.freely
}
if (!(defaultConfig.defaultPermission in defaultConfig.permission)) {
defaultConfig.defaultPermission = defaultConfig.permission.editable
}
// cache result, cannot change config in runtime!!!
defaultConfig.isStandardHTTPsPort = (function isStandardHTTPsPort () {
return defaultConfig.useSSL && defaultConfig.port === 443
})()
defaultConfig.isStandardHTTPPort = (function isStandardHTTPPort () {
return !defaultConfig.useSSL && defaultConfig.port === 80
})()
// cache serverURL
defaultConfig.serverURL = (function getserverurl () {
var url = ''
if (defaultConfig.domain) {
var protocol = defaultConfig.protocolUseSSL ? 'https://' : 'http://'
url = protocol + defaultConfig.domain
if (defaultConfig.urlAddPort) {
if (!defaultConfig.isStandardHTTPPort || !defaultConfig.isStandardHTTPsPort) {
url += ':' + defaultConfig.port
}
}
}
if (defaultConfig.urlPath) {
url += '/' + defaultConfig.urlPath
}
return url
})()
if (defaultConfig.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.')
}
defaultConfig.Environment = Environment
// auth method
defaultConfig.isFacebookEnable = defaultConfig.facebook.clientID && defaultConfig.facebook.clientSecret
defaultConfig.isGoogleEnable = defaultConfig.google.clientID && defaultConfig.google.clientSecret
defaultConfig.isDropboxEnable = defaultConfig.dropbox.clientID && defaultConfig.dropbox.clientSecret
defaultConfig.isTwitterEnable = defaultConfig.twitter.consumerKey && defaultConfig.twitter.consumerSecret
defaultConfig.isEmailEnable = defaultConfig.email
defaultConfig.isOpenIDEnable = defaultConfig.openID
defaultConfig.isGitHubEnable = defaultConfig.github.clientID && defaultConfig.github.clientSecret
defaultConfig.isGitLabEnable = defaultConfig.gitlab.clientID && defaultConfig.gitlab.clientSecret
defaultConfig.isLDAPEnable = defaultConfig.ldap.url
defaultConfig.isSAMLEnable = defaultConfig.saml.idpSsoUrl
defaultConfig.isOAuth2Enable = defaultConfig.oauth2.clientID && defaultConfig.oauth2.clientSecret
// Check gitlab api version
if (defaultConfig.gitlab && defaultConfig.gitlab.version !== 'v4' && defaultConfig.gitlab.version !== 'v3') {
logger.warn('config.js contains wrong version (' + defaultConfig.gitlab.version + ') for gitlab api; it should be \'v3\' or \'v4\'. Defaulting to v4')
defaultConfig.gitlab.version = 'v4'
}
// If gitlab scope is api, enable snippets Export/import
defaultConfig.isGitlabSnippetsEnable = (!defaultConfig.gitlab.scope || defaultConfig.gitlab.scope === 'api') && defaultConfig.isGitLabEnable
// Only update i18n files in development setups
defaultConfig.updateI18nFiles = (env === Environment.development)
// merge legacy values
let keys = Object.keys(defaultConfig)
const uppercase = /[A-Z]/
for (let i = keys.length; i--;) {
let lowercaseKey = keys[i].toLowerCase()
// 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]) &&
defaultConfig[lowercaseKey] !== undefined &&
fileConfig[keys[i]] === undefined) {
logger.warn('config.js contains deprecated lowercase setting for ' + keys[i] + '. Please change your config.js file to replace ' + lowercaseKey + ' with ' + keys[i])
defaultConfig[keys[i]] = defaultConfig[lowercaseKey]
}
}
// 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) {
logger.warn('Using legacy HMD prefix for environment variables. Please change your variables in future. For details see: https://github.com/codimd/server#environment-variables-will-overwrite-other-server-configs')
}
// Generate session secret if it stays on default values
if (defaultConfig.sessionSecret === 'secret') {
logger.warn('Session secret not set. Using random generated one. Please set `sessionSecret` in your config.js file. All users will be logged out.')
defaultConfig.sessionSecret = crypto.randomBytes(Math.ceil(defaultConfig.sessionSecretLen / 2)) // generate crypto graphic random number
.toString('hex') // convert to hexadecimal format
.slice(0, defaultConfig.sessionSecretLen) // return required number of characters
}
// Validate upload upload providers
if (['filesystem', 's3', 'minio', 'imgur', 'azure', 'lutim'].indexOf(defaultConfig.imageUploadType) === -1) {
logger.error('"imageuploadtype" is not correctly set. Please use "filesystem", "s3", "minio", "azure", "lutim" or "imgur". Defaulting to "filesystem"')
defaultConfig.imageUploadType = 'filesystem'
}
// figure out mime types for image uploads
switch (defaultConfig.imageUploadType) {
case 'imgur':
defaultConfig.allowedUploadMimeTypes = [
'image/jpeg',
'image/png',
'image/jpg',
'image/gif'
]
break
default:
defaultConfig.allowedUploadMimeTypes = [
'image/jpeg',
'image/png',
'image/jpg',
'image/gif',
'image/svg+xml'
]
}
// generate correct path
defaultConfig.sslCAPath.forEach(function (capath, i, array) {
array[i] = path.resolve(appRootPath, capath)
})
defaultConfig.sslCertPath = path.resolve(appRootPath, defaultConfig.sslCertPath)
defaultConfig.sslKeyPath = path.resolve(appRootPath, defaultConfig.sslKeyPath)
defaultConfig.dhParamPath = path.resolve(appRootPath, defaultConfig.dhParamPath)
defaultConfig.viewPath = path.resolve(appRootPath, defaultConfig.viewPath)
defaultConfig.tmpPath = path.resolve(appRootPath, defaultConfig.tmpPath)
defaultConfig.publicPath = path.resolve(appRootPath, defaultConfig.publicPath)
defaultConfig.defaultNotePath = path.resolve(appRootPath, defaultConfig.defaultNotePath)
defaultConfig.docsPath = path.resolve(appRootPath, defaultConfig.docsPath)
defaultConfig.uploadsPath = path.resolve(appRootPath, defaultConfig.uploadsPath)
defaultConfig.localesPath = path.resolve(appRootPath, defaultConfig.localesPath)
// make config readonly
export const config = deepFreeze(defaultConfig)