Move old backend code to old_src folder

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2020-07-24 21:06:55 +02:00
parent c42d2223e8
commit 7b9f9a487b
No known key found for this signature in database
GPG key ID: 6017AF117F9756CB
97 changed files with 7 additions and 7 deletions

View file

@ -0,0 +1,122 @@
import os from 'os'
import { Config } from './interfaces'
import { Permission } from './enum'
export const defaultConfig: Config = {
permission: Permission,
domain: '',
urlPath: '',
host: '0.0.0.0',
port: 3000,
socket: {
group: undefined,
owner: undefined,
mode: undefined
},
loglevel: 'info',
urlAddPort: false,
allowOrigin: ['localhost'],
useSSL: false,
hsts: {
enable: true,
maxAgeSeconds: 60 * 60 * 24 * 365,
includeSubdomains: true,
preload: true
},
csp: {
enable: true,
directives: {},
addDefaults: true,
addDisqus: true,
addGoogleAnalytics: true,
upgradeInsecureRequests: 'auto',
reportURI: undefined
},
protocolUseSSL: false,
useCDN: false,
allowAnonymous: true,
allowAnonymousEdits: false,
allowFreeURL: false,
forbiddenNoteIDs: ['robots.txt', 'favicon.ico', 'api', 'build', 'css', 'docs', 'fonts', 'js', 'uploads', 'vendor', 'views'],
defaultPermission: 'editable',
dbURL: '',
db: {},
// ssl path
sslKeyPath: '',
sslCertPath: '',
sslCAPath: [],
dhParamPath: '',
// other path
publicPath: './public',
viewPath: './public/views',
tmpPath: os.tmpdir(),
defaultNotePath: './public/default.md',
docsPath: './public/docs',
uploadsPath: './public/uploads',
localesPath: './locales',
// session
sessionName: 'connect.sid',
sessionSecret: 'secret',
sessionSecretLen: 128,
sessionLife: 14 * 24 * 60 * 60 * 1000, // 14 days
staticCacheTime: 1 * 24 * 60 * 60 * 1000, // 1 day
// socket.io
heartbeatInterval: 5000,
heartbeatTimeout: 10000,
// too busy timeout
tooBusyLag: 70,
// document
documentMaxLength: 100000,
// image upload setting, available options are imgur/s3/filesystem/azure/lutim
imageUploadType: 'filesystem',
lutim: {
url: 'https://framapic.org/'
},
minio: {
accessKey: undefined,
secretKey: undefined,
endPoint: undefined,
secure: true,
port: 9000
},
gitlab: {
baseURL: undefined,
clientID: undefined,
clientSecret: undefined,
scope: undefined,
version: 'v4'
},
saml: {
idpSsoUrl: undefined,
idpCert: undefined,
issuer: undefined,
identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
disableRequestedAuthnContext: false,
groupAttribute: undefined,
externalGroups: [],
requiredGroups: [],
attribute: {
id: undefined,
username: undefined,
email: undefined
}
},
email: true,
allowEmailRegister: true,
allowGravatar: true,
openID: false,
// linkifyHeaderStyle - How is a header text converted into a link id.
// Header Example: "3.1. Good Morning my Friend! - Do you have 5$?"
// * 'keep-case' is the legacy CodiMD value.
// Generated id: "31-Good-Morning-my-Friend---Do-you-have-5"
// * 'lower-case' is the same like legacy (see above), but converted to lower-case.
// Generated id: "#31-good-morning-my-friend---do-you-have-5"
// * 'gfm' _GitHub-Flavored Markdown_ style as described here:
// https://gist.github.com/asabaylus/3071099#gistcomment-1593627
// It works like 'lower-case', but making sure the ID is unique.
// This is What GitHub, GitLab and (hopefully) most other tools use.
// Generated id: "31-good-morning-my-friend---do-you-have-5"
// 2nd appearance: "31-good-morning-my-friend---do-you-have-5-1"
// 3rd appearance: "31-good-morning-my-friend---do-you-have-5-2"
linkifyHeaderStyle: 'keep-case'
}

View file

@ -0,0 +1,15 @@
import fs from 'fs'
function getFile (path): string {
if (fs.existsSync(path)) {
return path
}
return ''
}
export const defaultSSL = {
sslKeyPath: getFile('/run/secrets/key.pem'),
sslCertPath: getFile('/run/secrets/cert.pem'),
sslCAPath: getFile('/run/secrets/ca.pem') !== undefined ? [getFile('/run/secrets/ca.pem')] : [],
dhParamPath: getFile('/run/secrets/dhparam.pem')
}

View file

@ -0,0 +1,57 @@
import fs from 'fs'
import path from 'path'
const basePath = path.resolve('/run/secrets/')
function getSecret (secret): string | undefined {
const filePath = path.join(basePath, secret)
if (fs.existsSync(filePath)) return fs.readFileSync(filePath, 'utf-8')
return undefined
}
export let dockerSecret: { s3: { accessKeyId: string | undefined; secretAccessKey: string | undefined }; github: { clientID: string | undefined; clientSecret: string | undefined }; facebook: { clientID: string | undefined; clientSecret: string | undefined }; google: { clientID: string | undefined; hostedDomain: string | undefined; clientSecret: string | undefined }; sessionSecret: string | undefined; sslKeyPath: string | undefined; twitter: { consumerSecret: string | undefined; consumerKey: string | undefined }; dropbox: { clientID: string | undefined; clientSecret: string | undefined; appKey: string | undefined }; gitlab: { clientID: string | undefined; clientSecret: string | undefined }; imgur: string | undefined; sslCertPath: string | undefined; sslCAPath: (string | undefined)[]; dhParamPath: string | undefined; dbURL: string | undefined; azure: { connectionString: string | undefined } }
if (fs.existsSync(basePath)) {
dockerSecret = {
dbURL: getSecret('dbURL'),
sessionSecret: getSecret('sessionsecret'),
sslKeyPath: getSecret('sslkeypath'),
sslCertPath: getSecret('sslcertpath'),
sslCAPath: [getSecret('sslcapath')],
dhParamPath: getSecret('dhparampath'),
s3: {
accessKeyId: getSecret('s3_acccessKeyId'),
secretAccessKey: getSecret('s3_secretAccessKey')
},
azure: {
connectionString: getSecret('azure_connectionString')
},
facebook: {
clientID: getSecret('facebook_clientID'),
clientSecret: getSecret('facebook_clientSecret')
},
twitter: {
consumerKey: getSecret('twitter_consumerKey'),
consumerSecret: getSecret('twitter_consumerSecret')
},
github: {
clientID: getSecret('github_clientID'),
clientSecret: getSecret('github_clientSecret')
},
gitlab: {
clientID: getSecret('gitlab_clientID'),
clientSecret: getSecret('gitlab_clientSecret')
},
dropbox: {
clientID: getSecret('dropbox_clientID'),
clientSecret: getSecret('dropbox_clientSecret'),
appKey: getSecret('dropbox_appKey')
},
google: {
clientID: getSecret('google_clientID'),
clientSecret: getSecret('google_clientSecret'),
hostedDomain: getSecret('google_hostedDomain')
},
imgur: getSecret('imgur_clientid')
}
}

View file

@ -0,0 +1,29 @@
export interface Environment {
development: string;
production: string;
test: string;
}
export const Environment: Environment = {
development: 'development',
production: 'production',
test: 'test'
}
export interface Permission {
freely: string;
editable: string;
limited: string;
locked: string;
protected: string;
private: string;
}
export const Permission: Permission = {
freely: 'freely',
editable: 'editable',
limited: 'limited',
locked: 'locked',
protected: 'protected',
private: 'private'
}

View file

@ -0,0 +1,138 @@
import { toArrayConfig, toBooleanConfig, toIntegerConfig } from './utils'
export const environment = {
sourceURL: process.env.CMD_SOURCE_URL,
domain: process.env.CMD_DOMAIN,
urlPath: process.env.CMD_URL_PATH,
host: process.env.CMD_HOST,
port: toIntegerConfig(process.env.CMD_PORT),
path: process.env.CMD_PATH,
socket: {
group: process.env.CMD_SOCKET_GROUP,
owner: process.env.CMD_SOCKET_OWNER,
mode: process.env.CMD_SOCKET_MODE
},
loglevel: process.env.CMD_LOGLEVEL,
urlAddPort: toBooleanConfig(process.env.CMD_URL_ADDPORT),
useSSL: toBooleanConfig(process.env.CMD_USESSL),
hsts: {
enable: toBooleanConfig(process.env.CMD_HSTS_ENABLE),
maxAgeSeconds: toIntegerConfig(process.env.CMD_HSTS_MAX_AGE),
includeSubdomains: toBooleanConfig(process.env.CMD_HSTS_INCLUDE_SUBDOMAINS),
preload: toBooleanConfig(process.env.CMD_HSTS_PRELOAD)
},
csp: {
enable: toBooleanConfig(process.env.CMD_CSP_ENABLE),
reportURI: process.env.CMD_CSP_REPORTURI
},
protocolUseSSL: toBooleanConfig(process.env.CMD_PROTOCOL_USESSL),
allowOrigin: toArrayConfig(process.env.CMD_ALLOW_ORIGIN),
useCDN: toBooleanConfig(process.env.CMD_USECDN),
allowAnonymous: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS),
allowAnonymousEdits: toBooleanConfig(process.env.CMD_ALLOW_ANONYMOUS_EDITS),
allowFreeURL: toBooleanConfig(process.env.CMD_ALLOW_FREEURL),
forbiddenNoteIDs: toArrayConfig(process.env.CMD_FORBIDDEN_NOTE_IDS),
defaultPermission: process.env.CMD_DEFAULT_PERMISSION,
dbURL: process.env.CMD_DB_URL,
sessionSecret: process.env.CMD_SESSION_SECRET,
sessionLife: toIntegerConfig(process.env.CMD_SESSION_LIFE),
tooBusyLag: toIntegerConfig(process.env.CMD_TOOBUSY_LAG),
imageUploadType: process.env.CMD_IMAGE_UPLOAD_TYPE,
imgur: {
clientID: process.env.CMD_IMGUR_CLIENTID
},
s3: {
accessKeyId: process.env.CMD_S3_ACCESS_KEY_ID,
secretAccessKey: process.env.CMD_S3_SECRET_ACCESS_KEY,
region: process.env.CMD_S3_REGION,
endpoint: process.env.CMD_S3_ENDPOINT
},
minio: {
accessKey: process.env.CMD_MINIO_ACCESS_KEY,
secretKey: process.env.CMD_MINIO_SECRET_KEY,
endPoint: process.env.CMD_MINIO_ENDPOINT,
secure: toBooleanConfig(process.env.CMD_MINIO_SECURE),
port: toIntegerConfig(process.env.CMD_MINIO_PORT)
},
lutim: {
url: process.env.CMD_LUTIM_URL
},
s3bucket: process.env.CMD_S3_BUCKET,
azure: {
connectionString: process.env.CMD_AZURE_CONNECTION_STRING,
container: process.env.CMD_AZURE_CONTAINER
},
facebook: {
clientID: process.env.CMD_FACEBOOK_CLIENTID,
clientSecret: process.env.CMD_FACEBOOK_CLIENTSECRET
},
twitter: {
consumerKey: process.env.CMD_TWITTER_CONSUMERKEY,
consumerSecret: process.env.CMD_TWITTER_CONSUMERSECRET
},
github: {
clientID: process.env.CMD_GITHUB_CLIENTID,
clientSecret: process.env.CMD_GITHUB_CLIENTSECRET
},
gitlab: {
baseURL: process.env.CMD_GITLAB_BASEURL,
clientID: process.env.CMD_GITLAB_CLIENTID,
clientSecret: process.env.CMD_GITLAB_CLIENTSECRET,
scope: process.env.CMD_GITLAB_SCOPE
},
oauth2: {
providerName: process.env.CMD_OAUTH2_PROVIDERNAME,
baseURL: process.env.CMD_OAUTH2_BASEURL,
userProfileURL: process.env.CMD_OAUTH2_USER_PROFILE_URL,
userProfileUsernameAttr: process.env.CMD_OAUTH2_USER_PROFILE_USERNAME_ATTR,
userProfileDisplayNameAttr: process.env.CMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR,
userProfileEmailAttr: process.env.CMD_OAUTH2_USER_PROFILE_EMAIL_ATTR,
tokenURL: process.env.CMD_OAUTH2_TOKEN_URL,
authorizationURL: process.env.CMD_OAUTH2_AUTHORIZATION_URL,
clientID: process.env.CMD_OAUTH2_CLIENT_ID,
clientSecret: process.env.CMD_OAUTH2_CLIENT_SECRET,
scope: process.env.CMD_OAUTH2_SCOPE
},
dropbox: {
clientID: process.env.CMD_DROPBOX_CLIENTID,
clientSecret: process.env.CMD_DROPBOX_CLIENTSECRET,
appKey: process.env.CMD_DROPBOX_APPKEY
},
google: {
clientID: process.env.CMD_GOOGLE_CLIENTID,
clientSecret: process.env.CMD_GOOGLE_CLIENTSECRET,
hostedDomain: process.env.CMD_GOOGLE_HOSTEDDOMAIN
},
ldap: {
providerName: process.env.CMD_LDAP_PROVIDERNAME,
url: process.env.CMD_LDAP_URL,
bindDn: process.env.CMD_LDAP_BINDDN,
bindCredentials: process.env.CMD_LDAP_BINDCREDENTIALS,
searchBase: process.env.CMD_LDAP_SEARCHBASE,
searchFilter: process.env.CMD_LDAP_SEARCHFILTER,
searchAttributes: toArrayConfig(process.env.CMD_LDAP_SEARCHATTRIBUTES),
usernameField: process.env.CMD_LDAP_USERNAMEFIELD,
useridField: process.env.CMD_LDAP_USERIDFIELD,
tlsca: process.env.CMD_LDAP_TLS_CA
},
saml: {
idpSsoUrl: process.env.CMD_SAML_IDPSSOURL,
idpCert: process.env.CMD_SAML_IDPCERT,
issuer: process.env.CMD_SAML_ISSUER,
identifierFormat: process.env.CMD_SAML_IDENTIFIERFORMAT,
disableRequestedAuthnContext: toBooleanConfig(process.env.CMD_SAML_DISABLEREQUESTEDAUTHNCONTEXT),
groupAttribute: process.env.CMD_SAML_GROUPATTRIBUTE,
externalGroups: toArrayConfig(process.env.CMD_SAML_EXTERNALGROUPS, '|', []),
requiredGroups: toArrayConfig(process.env.CMD_SAML_REQUIREDGROUPS, '|', []),
attribute: {
id: process.env.CMD_SAML_ATTRIBUTE_ID,
username: process.env.CMD_SAML_ATTRIBUTE_USERNAME,
email: process.env.CMD_SAML_ATTRIBUTE_EMAIL
}
},
email: toBooleanConfig(process.env.CMD_EMAIL),
allowEmailRegister: toBooleanConfig(process.env.CMD_ALLOW_EMAIL_REGISTER),
allowGravatar: toBooleanConfig(process.env.CMD_ALLOW_GRAVATAR),
openID: toBooleanConfig(process.env.CMD_OPENID),
linkifyHeaderStyle: process.env.CMD_LINKIFY_HEADER_STYLE
}

View file

@ -0,0 +1,118 @@
import { toArrayConfig, toBooleanConfig, toIntegerConfig } from './utils'
export const hackmdEnvironment = {
domain: process.env.HMD_DOMAIN,
urlPath: process.env.HMD_URL_PATH,
port: toIntegerConfig(process.env.HMD_PORT),
urlAddPort: toBooleanConfig(process.env.HMD_URL_ADDPORT),
useSSL: toBooleanConfig(process.env.HMD_USESSL),
hsts: {
enable: toBooleanConfig(process.env.HMD_HSTS_ENABLE),
maxAgeSeconds: toIntegerConfig(process.env.HMD_HSTS_MAX_AGE),
includeSubdomains: toBooleanConfig(process.env.HMD_HSTS_INCLUDE_SUBDOMAINS),
preload: toBooleanConfig(process.env.HMD_HSTS_PRELOAD)
},
csp: {
enable: toBooleanConfig(process.env.HMD_CSP_ENABLE),
reportURI: process.env.HMD_CSP_REPORTURI
},
protocolUseSSL: toBooleanConfig(process.env.HMD_PROTOCOL_USESSL),
allowOrigin: toArrayConfig(process.env.HMD_ALLOW_ORIGIN),
useCDN: toBooleanConfig(process.env.HMD_USECDN),
allowAnonymous: toBooleanConfig(process.env.HMD_ALLOW_ANONYMOUS),
allowAnonymousEdits: toBooleanConfig(process.env.HMD_ALLOW_ANONYMOUS_EDITS),
allowFreeURL: toBooleanConfig(process.env.HMD_ALLOW_FREEURL),
defaultPermission: process.env.HMD_DEFAULT_PERMISSION,
dbURL: process.env.HMD_DB_URL,
sessionSecret: process.env.HMD_SESSION_SECRET,
sessionLife: toIntegerConfig(process.env.HMD_SESSION_LIFE),
imageUploadType: process.env.HMD_IMAGE_UPLOAD_TYPE,
imgur: {
clientID: process.env.HMD_IMGUR_CLIENTID
},
s3: {
accessKeyId: process.env.HMD_S3_ACCESS_KEY_ID,
secretAccessKey: process.env.HMD_S3_SECRET_ACCESS_KEY,
region: process.env.HMD_S3_REGION
},
minio: {
accessKey: process.env.HMD_MINIO_ACCESS_KEY,
secretKey: process.env.HMD_MINIO_SECRET_KEY,
endPoint: process.env.HMD_MINIO_ENDPOINT,
secure: toBooleanConfig(process.env.HMD_MINIO_SECURE),
port: toIntegerConfig(process.env.HMD_MINIO_PORT)
},
s3bucket: process.env.HMD_S3_BUCKET,
azure: {
connectionString: process.env.HMD_AZURE_CONNECTION_STRING,
container: process.env.HMD_AZURE_CONTAINER
},
facebook: {
clientID: process.env.HMD_FACEBOOK_CLIENTID,
clientSecret: process.env.HMD_FACEBOOK_CLIENTSECRET
},
twitter: {
consumerKey: process.env.HMD_TWITTER_CONSUMERKEY,
consumerSecret: process.env.HMD_TWITTER_CONSUMERSECRET
},
github: {
clientID: process.env.HMD_GITHUB_CLIENTID,
clientSecret: process.env.HMD_GITHUB_CLIENTSECRET
},
gitlab: {
baseURL: process.env.HMD_GITLAB_BASEURL,
clientID: process.env.HMD_GITLAB_CLIENTID,
clientSecret: process.env.HMD_GITLAB_CLIENTSECRET,
scope: process.env.HMD_GITLAB_SCOPE
},
oauth2: {
baseURL: process.env.HMD_OAUTH2_BASEURL,
userProfileURL: process.env.HMD_OAUTH2_USER_PROFILE_URL,
userProfileUsernameAttr: process.env.HMD_OAUTH2_USER_PROFILE_USERNAME_ATTR,
userProfileDisplayNameAttr: process.env.HMD_OAUTH2_USER_PROFILE_DISPLAY_NAME_ATTR,
userProfileEmailAttr: process.env.HMD_OAUTH2_USER_PROFILE_EMAIL_ATTR,
tokenURL: process.env.HMD_OAUTH2_TOKEN_URL,
authorizationURL: process.env.HMD_OAUTH2_AUTHORIZATION_URL,
clientID: process.env.HMD_OAUTH2_CLIENT_ID,
clientSecret: process.env.HMD_OAUTH2_CLIENT_SECRET,
scope: process.env.HMD_OAUTH2_SCOPE
},
dropbox: {
clientID: process.env.HMD_DROPBOX_CLIENTID,
clientSecret: process.env.HMD_DROPBOX_CLIENTSECRET,
appKey: process.env.HMD_DROPBOX_APPKEY
},
google: {
clientID: process.env.HMD_GOOGLE_CLIENTID,
clientSecret: process.env.HMD_GOOGLE_CLIENTSECRET
},
ldap: {
providerName: process.env.HMD_LDAP_PROVIDERNAME,
url: process.env.HMD_LDAP_URL,
bindDn: process.env.HMD_LDAP_BINDDN,
bindCredentials: process.env.HMD_LDAP_BINDCREDENTIALS,
searchBase: process.env.HMD_LDAP_SEARCHBASE,
searchFilter: process.env.HMD_LDAP_SEARCHFILTER,
searchAttributes: toArrayConfig(process.env.HMD_LDAP_SEARCHATTRIBUTES),
usernameField: process.env.HMD_LDAP_USERNAMEFIELD,
useridField: process.env.HMD_LDAP_USERIDFIELD,
tlsca: process.env.HMD_LDAP_TLS_CA
},
saml: {
idpSsoUrl: process.env.HMD_SAML_IDPSSOURL,
idpCert: process.env.HMD_SAML_IDPCERT,
issuer: process.env.HMD_SAML_ISSUER,
identifierFormat: process.env.HMD_SAML_IDENTIFIERFORMAT,
disableRequestedAuthnContext: toBooleanConfig(process.env.HMD_SAML_DISABLEREQUESTEDAUTHNCONTEXT),
groupAttribute: process.env.HMD_SAML_GROUPATTRIBUTE,
externalGroups: toArrayConfig(process.env.HMD_SAML_EXTERNALGROUPS, '|', []),
requiredGroups: toArrayConfig(process.env.HMD_SAML_REQUIREDGROUPS, '|', []),
attribute: {
id: process.env.HMD_SAML_ATTRIBUTE_ID,
username: process.env.HMD_SAML_ATTRIBUTE_USERNAME,
email: process.env.HMD_SAML_ATTRIBUTE_EMAIL
}
},
email: toBooleanConfig(process.env.HMD_EMAIL),
allowEmailRegister: toBooleanConfig(process.env.HMD_ALLOW_EMAIL_REGISTER)
}

211
old_src/lib/config/index.ts Normal file
View file

@ -0,0 +1,211 @@
import crypto from 'crypto'
import fs from 'fs'
import path from 'path'
import { merge } from 'lodash'
import { Environment, Permission } from './enum'
import { logger } from '../logger'
import { getGitCommit, getGitHubURL } from './utils'
import { defaultConfig } from './default'
import { defaultSSL } from './defaultSSL'
import { oldDefault } from './oldDefault'
import { oldEnvironment } from './oldEnvironment'
import { hackmdEnvironment } from './hackmdEnvironment'
import { environment } from './environment'
import { dockerSecret } from './dockerSecret'
import deepFreeze = require('deep-freeze')
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
// TODO: There are other ways to geht the current version
// eslint-disable-next-line @typescript-eslint/no-var-requires
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
merge(defaultConfig, defaultSSL)
merge(defaultConfig, oldDefault)
merge(defaultConfig, debugConfig)
merge(defaultConfig, packageConfig)
merge(defaultConfig, fileConfig)
merge(defaultConfig, oldEnvironment)
merge(defaultConfig, hackmdEnvironment)
merge(defaultConfig, environment)
merge(defaultConfig, 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) {
const ca = defaultConfig.ldap.tlsca.split(',')
const caContent: string[] = []
for (const i of ca) {
if (fs.existsSync(i)) {
caContent.push(fs.readFileSync(i, 'utf8'))
}
}
const 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 (): boolean {
return defaultConfig.useSSL && defaultConfig.port === 443
})()
defaultConfig.isStandardHTTPPort = (function isStandardHTTPPort (): boolean {
return !defaultConfig.useSSL && defaultConfig.port === 80
})()
// cache serverURL
defaultConfig.serverURL = (function getserverurl (): string {
let url = ''
if (defaultConfig.domain) {
const 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
const keys = Object.keys(defaultConfig)
const uppercase = /[A-Z]/
for (let i = keys.length; i--;) {
const 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().includes('HMD_')) {
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'].includes(defaultConfig.imageUploadType)) {
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)

View file

@ -0,0 +1,159 @@
import { Permission } from './enum'
import { IHelmetContentSecurityPolicyDirectives } from 'helmet'
type CSPDirectives = IHelmetContentSecurityPolicyDirectives
export interface Config {
permission: Permission;
domain: string;
urlPath: string;
host: string;
port: number;
loglevel: string;
urlAddPort: boolean;
allowOrigin: string[];
useSSL: boolean;
hsts: {
enable: boolean;
maxAgeSeconds: number;
includeSubdomains: boolean;
preload: boolean;
};
csp: {
enable: boolean;
directives?: CSPDirectives;
addDefaults: boolean;
addDisqus: boolean;
addGoogleAnalytics: boolean;
upgradeInsecureRequests: string | boolean;
reportURI?: string;
};
protocolUseSSL: boolean;
useCDN: boolean;
allowAnonymous: boolean;
allowAnonymousEdits: boolean;
allowFreeURL: boolean;
forbiddenNoteIDs: string[];
defaultPermission: string;
dbURL: string;
db;
sslKeyPath: string;
sslCertPath: string;
sslCAPath: string[];
dhParamPath: string;
publicPath: string;
viewPath: string;
tmpPath: string;
defaultNotePath: string;
docsPath: string;
uploadsPath: string;
sessionName: string;
sessionSecret: string;
sessionSecretLen: number;
sessionLife: number;
staticCacheTime: number;
heartbeatInterval: number;
heartbeatTimeout: number;
tooBusyLag: number;
documentMaxLength: number;
imageUploadType: 'azure' | 'filesystem' | 'imgur' | 'lutim' | 'minio' | 's3';
lutim?: {
url: string;
};
imgur?: {
clientID: string;
};
s3?: {
accessKeyId: string;
secretAccessKey: string;
region: string;
};
minio?: {
accessKey?: string;
secretKey?: string;
endPoint?: string;
secure?: boolean;
port?: number;
};
s3bucket?: string;
azure?: {
connectionString: string;
container: string;
};
oauth2?: {
providerName: string;
authorizationURL: string;
tokenURL: string;
clientID: string;
clientSecret: string;
};
facebook?: {
clientID: string;
clientSecret: string;
};
twitter?: {
consumerKey: string;
consumerSecret: string;
};
github?: {
clientID: string;
clientSecret: string;
};
gitlab?: {
baseURL?: string;
clientID?: string;
clientSecret?: string;
scope?: string;
version?: string;
};
dropbox?: {
clientID: string;
clientSecret: string;
appKey: string;
};
google?: {
clientID: string;
clientSecret: string;
hostedDomain: string;
};
ldap?: {
providerName: string;
url: string;
bindDn: string;
bindCredentials: string;
searchBase: string;
searchFilter: string;
searchAttributes: string;
usernameField: string;
useridField: string;
tlsca: string;
starttls?: boolean;
tlsOptions: {
ca: string[];
};
};
saml?: {
idpSsoUrl?: string;
idpCert?: string;
issuer?: string;
identifierFormat?: string;
disableRequestedAuthnContext?: boolean;
groupAttribute?: string;
externalGroups?: string[];
requiredGroups?: string[];
attribute?: {
id?: string;
username?: string;
email?: string;
};
};
email: boolean;
allowEmailRegister: boolean;
allowGravatar: boolean;
openID: boolean;
linkifyHeaderStyle: string;
// TODO: Remove escape hatch for dynamically added properties
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[propName: string]: any;
}

View file

@ -0,0 +1,39 @@
export const oldDefault = {
urlpath: undefined,
urladdport: undefined,
alloworigin: undefined,
usessl: undefined,
protocolusessl: undefined,
usecdn: undefined,
allowanonymous: undefined,
allowanonymousedits: undefined,
allowfreeurl: undefined,
defaultpermission: undefined,
dburl: undefined,
// ssl path
sslkeypath: undefined,
sslcertpath: undefined,
sslcapath: undefined,
dhparampath: undefined,
// other path
tmppath: undefined,
defaultnotepath: undefined,
docspath: undefined,
indexpath: undefined,
hackmdpath: undefined,
errorpath: undefined,
prettypath: undefined,
slidepath: undefined,
// session
sessionname: undefined,
sessionsecret: undefined,
sessionlife: undefined,
staticcachetime: undefined,
// socket.io
heartbeatinterval: undefined,
heartbeattimeout: undefined,
// document
documentmaxlength: undefined,
imageuploadtype: undefined,
allowemailregister: undefined
}

View file

@ -0,0 +1,8 @@
import { toBooleanConfig } from './utils'
export const oldEnvironment = {
debug: toBooleanConfig(process.env.DEBUG),
dburl: process.env.DATABASE_URL,
urlpath: process.env.URL_PATH,
port: process.env.PORT
}

View file

@ -0,0 +1,53 @@
import fs from 'fs'
import path from 'path'
export function toBooleanConfig (configValue: string | boolean | undefined): boolean | undefined {
if (typeof configValue === 'string') {
return (configValue === 'true')
}
return configValue
}
export function toArrayConfig (configValue: string | undefined, separator = ',', fallback = []): string[] {
if (configValue) {
return (configValue.split(separator).map(arrayItem => arrayItem.trim()))
}
return fallback
}
export function toIntegerConfig (configValue): number {
if (configValue && typeof configValue === 'string') {
return parseInt(configValue)
}
return configValue
}
export function getGitCommit (repodir): string {
if (!fs.existsSync(repodir + '/.git/HEAD')) {
return ''
}
let reference = fs.readFileSync(repodir + '/.git/HEAD', 'utf8')
if (reference.startsWith('ref: ')) {
reference = reference.substr(5).replace('\n', '')
reference = fs.readFileSync(path.resolve(repodir + '/.git', reference), 'utf8')
}
reference = reference.replace('\n', '')
return reference
}
export function getGitHubURL (repo, reference): string {
// if it's not a github reference, we handle handle that anyway
if (!repo.startsWith('https://github.com') && !repo.startsWith('git@github.com')) {
return repo
}
if (repo.startsWith('git@github.com') || repo.startsWith('ssh://git@github.com')) {
repo = repo.replace(/^(ssh:\/\/)?git@github.com:/, 'https://github.com/')
}
if (repo.endsWith('.git')) {
repo = repo.replace(/\.git$/, '/')
} else if (!repo.endsWith('/')) {
repo = repo + '/'
}
return repo + 'tree/' + reference
}