From 268ce83784f7ff7ff074ce5479fcf790107bcbc0 Mon Sep 17 00:00:00 2001 From: Moe Date: Tue, 6 Apr 2021 20:55:16 -0700 Subject: [PATCH 1/6] update ldap account linking to use Alternate Login system --- definitions/en_CA.js | 150 ++++++------ languages/en_CA.json | 1 + libs/auth/google.js | 4 +- libs/auth/ldap.js | 220 ++++++++++++++++++ libs/auth/logins.js | 4 + libs/webServerPaths.js | 136 +---------- web/libs/js/dash2.ldapSignIn.js | 13 ++ .../{ => blocks}/loginTokenAddGoogle.ejs | 0 web/pages/blocks/loginTokenAddLDAP.ejs | 47 ++++ web/pages/index.ejs | 24 +- 10 files changed, 379 insertions(+), 220 deletions(-) create mode 100644 libs/auth/ldap.js create mode 100644 web/libs/js/dash2.ldapSignIn.js rename web/pages/{ => blocks}/loginTokenAddGoogle.ejs (100%) create mode 100644 web/pages/blocks/loginTokenAddLDAP.ejs diff --git a/definitions/en_CA.js b/definitions/en_CA.js index 2c079300..b93d16cc 100644 --- a/definitions/en_CA.js +++ b/definitions/en_CA.js @@ -4550,75 +4550,6 @@ module.exports = function(s,config,lang){ } ] }, - "LDAP": { - "evaluation":"details.use_ldap!=='0'", - "name": lang["LDAP"], - "color": "forestgreen", - "info": [ - { - "name": "detail=ldap_enable", - "selector":"ldap_i", - "field": lang.Enabled, - "description": "Enable LDAP authentication for this Group.", - "default": "0", - "example": "", - "fieldType": "select", - "possible": [ - { - "name": lang.No, - "value": "0" - }, - { - "name": lang.Yes, - "value": "1" - } - ] - }, - { - "form-group-class": "ldap_i_input ldap_i_1", - "name": "detail=ldap_url", - "field": lang.URL, - "description": "", - "example": "", - "possible": "" - }, - { - "placeholder":lang.Example + " : cn=admin,dc=test,dc=com", - "form-group-class": "ldap_i_input ldap_i_1", - "name": "detail=ldap_bindDN", - "field": lang.bindDN, - "description": "", - "example": "", - "possible": "" - }, - { - "form-group-class": "ldap_i_input ldap_i_1", - "name": "detail=ldap_bindCredentials", - "field": lang['Bind Credentials'], - "description": "", - "example": "", - "possible": "" - }, - { - "placeholder": "cn={{username}}", - "form-group-class": "ldap_i_input ldap_i_1", - "name": "detail=ldap_searchFilter", - "field": lang['Search Filter'], - "description": "", - "example": "", - "possible": "" - }, - { - "placeholder": "dc=test,dc=com", - "form-group-class": "ldap_i_input ldap_i_1", - "name": "detail=ldap_searchBase", - "field": lang['Search Base'], - "description": "", - "example": "", - "possible": "" - }, - ] - }, "Preferences": { "name": lang.Preferences, "color": "navy", @@ -5454,6 +5385,85 @@ module.exports = function(s,config,lang){ ] }, } - } + }, + "LDAP": { + "section": "LDAP", + "blocks": { + "LDAP": { + "evaluation":"details.use_ldap!=='0'", + "name": lang["LDAP"], + "color": "forestgreen", + "info": [ + { + "name": "ldap_enable", + "field": lang.Enabled, + "description": "Enable LDAP authentication for this Group.", + "default": "0", + "example": "", + "fieldType": "select", + "possible": [ + { + "name": lang.No, + "value": "0" + }, + { + "name": lang.Yes, + "value": "1" + } + ] + }, + { + "name": "ldap_url", + "field": lang.URL, + "description": "", + "example": "", + "possible": "" + }, + { + "name": "username", + "field": lang.Username, + "description": "", + "example": "", + "possible": "" + }, + { + "name": "password", + "field": lang.Password, + "description": "", + "example": "", + "possible": "" + }, + { + "name": "ldap_bindDN", + "field": lang.bindDN, + "description": "", + "example": "cn=admin,dc=test,dc=com", + "possible": "" + }, + { + "name": "ldap_searchBase", + "field": lang['Search Base'], + "description": "", + "example": "dc=test,dc=com", + "possible": "" + }, + { + "name": "ldap_searchFilter", + "field": lang['Search Filter'], + "description": "", + "example": "uid={{username}}", + "possible": "" + }, + { + "fieldType": "btn", + "forForm": true, + "attribute": `type="submit"`, + "class": `btn-success`, + "btnContent": `   ${lang['Save']}`, + }, + ] + } + } + } } } diff --git a/languages/en_CA.json b/languages/en_CA.json index 5e0717ff..39b7aa36 100644 --- a/languages/en_CA.json +++ b/languages/en_CA.json @@ -121,6 +121,7 @@ "Home": "Home", "alreadyLinked": "Already Linked to an Account", "Link Google Account": "Link Google Account", + "Link LDAP Account": "Link LDAP Account", "noLoginTokensAdded": "There are no Alternate Logins associated to this account.", "tokenNotUserBound": "This Login Handle is not linked to a user on this server!", "tokenNotUserBoundPt2": "Type your credentials then use the Google Sign-In button to link quickly.", diff --git a/libs/auth/google.js b/libs/auth/google.js index b92e77a0..920b0eb8 100644 --- a/libs/auth/google.js +++ b/libs/auth/google.js @@ -9,7 +9,7 @@ module.exports = (s,config,lang,app) => { bindLoginIdToUser, refreshLoginTokenAccessDate, } = require('./alternateLogins.js')(s,config,lang) - console.error(`Google App ID : ${config.appIdGoogleSignIn}`) + console.log(`Google App ID : ${config.appIdGoogleSignIn}`) const client = new OAuth2Client(config.appIdGoogleSignIn); async function verifyToken(userLoginToken) { const ticket = await client.verifyIdToken({ @@ -61,7 +61,7 @@ module.exports = (s,config,lang,app) => { return response } s.onProcessReady(() => { - config.renderPaths.loginTokenAddGoogle = `pages/loginTokenAddGoogle` + config.renderPaths.loginTokenAddGoogle = `pages/blocks/loginTokenAddGoogle` s.alternateLogins['google'] = async (params) => { const response = { ok: false } const loginToken = params.alternateLoginToken diff --git a/libs/auth/ldap.js b/libs/auth/ldap.js new file mode 100644 index 00000000..1364b9ff --- /dev/null +++ b/libs/auth/ldap.js @@ -0,0 +1,220 @@ +const LdapAuth = require('ldapauth-fork'); +module.exports = (s,config,lang,app) => { + const { + basicAuth, + } = require('./utils.js')(s,config,lang) + const { + getLoginToken, + deleteLoginToken, + bindLoginIdToUser, + refreshLoginTokenAccessDate, + } = require('./alternateLogins.js')(s,config,lang) + async function ldapAuth(params) { + return new Promise((resolve,reject) => { + const response = { ok: false } + let ldapUrl = params.url + ldapUrl = ldapUrl.startsWith('ldap://') ? ldapUrl : `ldap://${ldapUrl}` + const host = ldapUrl.split('://')[1] + const username = params.username// || 'ubuntu2' + const password = params.password// || 'moeiscool' + const bindDN = params.bindDN// || 'uid=ubuntu2,ou=People,dc=example,dc=com' + const searchBase = params.searchBase// || 'ou=People,dc=example,dc=com' + let searchFilter = params.searchFilter// || '(uid={{username}})' + searchFilter = searchFilter.startsWith('(') ? searchFilter : '(' + searchFilter + searchFilter = searchFilter.endsWith(')') ? searchFilter : searchFilter + ')' + const ldap = new LdapAuth({ + url: ldapUrl, + bindDN: bindDN, + bindCredentials: password, + searchBase: searchBase, + searchFilter: searchFilter, + reconnect: true + }) + + ldap.authenticate(username, password, function(err, user) { + if(err){ + response.err = err + }else{ + response.ok = true + response.user = { + id: host + '_' + user.uidNumber, + name: user.givenName + ' ' + user.sn, + } + } + resolve(response) + }) + }) + } + async function loginWithLdapAccount(params) { + const response = {ok: false, ldapSignedIn: false} + const tokenResponse = await ldapAuth(params) + if(tokenResponse.ok){ + const user = tokenResponse.user + response.ldapSignedIn = true + response.ldapUser = user + const foundToken = await getLoginToken(user.id,'ldap') + if(foundToken){ + const userResponse = await s.knexQueryPromise({ + action: "select", + columns: '*', + table: "Users", + where: [ + ['uid','=',foundToken.uid], + ['ke','=',foundToken.ke], + ], + limit: 1 + }) + response.ok = true + userResponse.rows[0].details = s.parseJSON(userResponse.rows[0].details) + response.user = userResponse.rows[0] + }else{ + response.msg = lang.tokenNotUserBound + // make new if no users? + } + } + return response + } + async function updateLdapBaseDetails(params,updateFields){ + const enabled = updateFields.ldap_enable + const url = updateFields.ldap_url + const bindDN = updateFields.ldap_bindDN + const searchBase = updateFields.ldap_searchBase + const searchFilter = updateFields.ldap_searchFilter + const userResponse = await s.knexQueryPromise({ + action: "select", + columns: "*", + table: "Users", + where: [ + ['ke','=',params.groupKey], + ['uid','=',params.userId], + ], + }) + const userDetails = JSON.parse(userResponse.rows[0].details) + userDetails.ldap_enable = enabled + userDetails.ldap_url = url + userDetails.ldap_bindDN = bindDN + userDetails.ldap_searchBase = searchBase + userDetails.ldap_searchFilter = searchFilter + await s.knexQueryPromise({ + action: "update", + table: "Users", + update: { + details: JSON.stringify(userDetails) + }, + where: [ + ['ke','=',params.groupKey], + ['uid','=',params.userId], + ] + }) + } + s.onProcessReady(() => { + config.renderPaths.loginTokenAddLDAP = `pages/blocks/loginTokenAddLDAP` + s.alternateLogins['ldap'] = async (params) => { + const response = { ok: false } + const groupKey = params.key + const userResponse = await s.knexQueryPromise({ + action: "select", + columns: "*", + table: "Users", + where: [ + ['ke','=',params.key], + ['details','NOT LIKE','%"sub"%'], + ], + }) + if(userResponse.rows[0]){ + const userDetails = JSON.parse(userResponse.rows[0].details) + const url = userDetails.ldap_url + const bindDN = userDetails.ldap_bindDN + const searchBase = userDetails.ldap_searchBase + const searchFilter = userDetails.ldap_searchFilter + const username = params.mail + const password = params.pass + const ldapLoginResponse = await loginWithLdapAccount({ + url: url, + username: username, + password: password, + bindDN: bindDN, + searchBase: searchBase, + searchFilter: searchFilter, + }) + if(ldapLoginResponse.user){ + const user = ldapLoginResponse.user + response.ok = true + response.user = user + refreshLoginTokenAccessDate(ldapLoginResponse.ldapUser.id,'ldap') + }else{ + response.msg = ldapLoginResponse.msg + } + } + return response + } + s.definitions["Account Settings"].blocks["AlternateLogins"].info.push({ + "form-group-class-pre-layer": "form-group", + "fieldType": "btn", + "class": `btn-info ldap-sign-in`, + "btnContent": `   ${lang['Link LDAP Account']}`, + }) + s.customAutoLoadTree['LibsJs'].push(`dash2.ldapSignIn.js`) + }) + /** + * API : Add Token Window (Sign-In to LDAP) (GET) + */ + app.get(config.webPaths.apiPrefix+':auth/loginTokenAddLDAP/:ke', function (req,res){ + s.auth(req.params,(user) => { + s.renderPage(req,res,config.renderPaths.loginTokenAddLDAP,{ + lang: lang, + define: s.getDefinitonFile(user.details.lang), + config: s.getConfigWithBranding(req.hostname), + $user: user + }) + },res,req); + }); + /** + * API : Add Token Window (Sign-In to LDAP) (POST) + */ + app.post(config.webPaths.apiPrefix+':auth/loginTokenAddLDAP/:ke', function (req,res){ + const response = {ok: false}; + s.auth(req.params,async (user) => { + const userId = user.uid + const groupKey = req.params.ke + const url = req.body.ldap_url + const bindDN = req.body.ldap_bindDN + const searchBase = req.body.ldap_searchBase + const searchFilter = req.body.ldap_searchFilter + const username = req.body.username + const password = req.body.password + const authPostBody = { + url: url, + username: username, + password: password, + bindDN: bindDN, + searchBase: searchBase, + searchFilter: searchFilter, + } + const tokenResponse = await ldapAuth(authPostBody) + if(tokenResponse.ok){ + const ldapUser = tokenResponse.user + const loginId = ldapUser.id + if(!user.details.sub){ + updateLdapBaseDetails({ + groupKey: groupKey, + userId: user.uid, + },req.body) + } + const bindResponse = await bindLoginIdToUser({ + loginId: loginId, + ke: groupKey, + uid: userId, + name: ldapUser.name, + type: 'ldap' + }) + response.ok = bindResponse.ok + response.msg = bindResponse.msg + } + s.closeJsonResponse(res,response) + },res,req); + }); + return { + loginWithLdapAccount: loginWithLdapAccount, + } +} diff --git a/libs/auth/logins.js b/libs/auth/logins.js index 8d56af62..c1edbe8d 100644 --- a/libs/auth/logins.js +++ b/libs/auth/logins.js @@ -5,4 +5,8 @@ module.exports = (s,config,lang,app) => { s.debugLog('Google') require('./google.js')(s,config,lang,app) } + if(config.allowLdapSignOn){ + s.debugLog('LDAP') + require('./ldap.js')(s,config,lang,app) + } } diff --git a/libs/webServerPaths.js b/libs/webServerPaths.js index 228196cf..7a7697e8 100644 --- a/libs/webServerPaths.js +++ b/libs/webServerPaths.js @@ -26,9 +26,6 @@ module.exports = function(s,config,lang,app,io){ twoFactorVerification, ldapLogin, } = require('./auth/utils.js')(s,config,lang) - if(config.productType === 'Pro'){ - var LdapAuth = require('ldapauth-fork'); - } s.renderPage = function(req,res,paths,passables,callback){ passables.window = {} passables.data = req.params @@ -447,138 +444,7 @@ module.exports = function(s,config,lang,app,io){ failedAuthentication(req.body.function,req.body.mail) } } - if(LdapAuth&&req.body.function==='ldap'&&req.body.key!==''){ - s.knexQuery({ - action: "select", - columns: "*", - table: "Users", - where: [ - ['ke','=',req.body.key], - ['details','NOT LIKE','%"sub"%'], - ], - },(err,r) => { - if(r&&r[0]){ - r=r[0] - r.details=JSON.parse(r.details) - r.lang=s.getLanguageFile(r.details.lang) - if(r.details.use_ldap!=='0'&&r.details.ldap_enable==='1'&&r.details.ldap_url&&r.details.ldap_url!==''){ - req.mailArray={} - req.body.mail.split(',').forEach(function(v){ - v=v.split('=') - req.mailArray[v[0]]=v[1] - }) - if(!r.details.ldap_bindDN||r.details.ldap_bindDN===''){ - r.details.ldap_bindDN=req.body.mail - } - if(!r.details.ldap_bindCredentials||r.details.ldap_bindCredentials===''){ - r.details.ldap_bindCredentials=req.body.pass - } - if(!r.details.ldap_searchFilter||r.details.ldap_searchFilter===''){ - r.details.ldap_searchFilter=req.body.mail - if(req.mailArray.cn){ - r.details.ldap_searchFilter='cn='+req.mailArray.cn - } - if(req.mailArray.uid){ - r.details.ldap_searchFilter='uid='+req.mailArray.uid - } - }else{ - r.details.ldap_searchFilter=r.details.ldap_searchFilter.replace('{{username}}',req.body.mail) - } - if(!r.details.ldap_searchBase||r.details.ldap_searchBase===''){ - r.details.ldap_searchBase='dc=test,dc=com' - } - req.auth = new LdapAuth({ - url:r.details.ldap_url, - bindDN:r.details.ldap_bindDN, - bindCredentials:r.details.ldap_bindCredentials, - searchBase:r.details.ldap_searchBase, - searchFilter:'('+r.details.ldap_searchFilter+')', - reconnect:true - }); - req.auth.on('error', function (err) { - console.error('LdapAuth: ', err); - }); - - req.auth.authenticate(req.body.mail, req.body.pass, function(err, user) { - if(user){ - //found user - if(!user.uid){ - user.uid=s.gid() - } - const userInfo = { - ke:req.body.key, - uid:user.uid, - auth:s.createHash(s.gid()), - mail:user.mail, - pass:s.createHash(req.body.pass), - details:JSON.stringify({ - sub:'1', - ldap:'1', - allmonitors:'1', - filter: {} - }) - } - s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP Success'],msg:{user:user}}) - s.knexQuery({ - action: "select", - columns: "*", - table: "Users", - where: [ - ['ke','=',req.body.key], - ['mail','=',user.cn], - ], - },function(err,rr) { - if(rr&&rr[0]){ - //already registered - rr = rr[0] - userInfo = rr; - rr.details = JSON.parse(rr.details) - userInfo.lang = s.getLanguageFile(rr.details.lang) - s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP User Authenticated'],msg:{user:user,shinobiUID:rr.uid}}) - s.knexQuery({ - action: "update", - table: "Users", - update: { - auth: userInfo.auth - }, - where: [ - ['ke','=',userInfo.ke], - ['uid','=',rr.uid], - ] - }) - }else{ - //new ldap login - s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP User is New'],msg:{info:r.lang['Creating New Account'],user:user}}) - userInfo.lang = r.lang - s.knexQuery({ - action: "insert", - table: "Users", - insert: userInfo, - }) - } - userInfo.details = JSON.stringify(userInfo.details) - userInfo.auth_token = userInfo.auth - userInfo.ok = true - checkRoute(req.body.function,userInfo) - }) - return - } - s.userLog({ke:req.body.key,mid:'$USER'},{type:r.lang['LDAP Failed'],msg:{err:err}}) - //no user - regularLogin() - }); - - req.auth.close(function(err) { - - }) - }else{ - regularLogin() - } - }else{ - regularLogin() - } - }) - }else if(req.body.function === 'super'){ + if(req.body.function === 'super'){ const superLoginResponse = await superLogin(req.body.mail,req.body.pass); if(superLoginResponse.ok){ renderPage(config.renderPaths.super,{ diff --git a/web/libs/js/dash2.ldapSignIn.js b/web/libs/js/dash2.ldapSignIn.js new file mode 100644 index 00000000..e1bffa2a --- /dev/null +++ b/web/libs/js/dash2.ldapSignIn.js @@ -0,0 +1,13 @@ +$(document).ready(function(){ + $('#settings').on('click','.ldap-sign-in',function(){ + var signInWindow = window.open(getApiPrefix('loginTokenAddLDAP'),'popup','width=300,height=300,scrollbars=no,resizable=no'); + if(!signInWindow || signInWindow.closed || typeof signInWindow.closed=='undefined'){ + alert(`Your Popup Blocker is disabling this feature.`) + }else{ + signInWindow.onbeforeunload = function(){ + drawAlternateLoginsToSettings() + } + } + return false; + }) +}) diff --git a/web/pages/loginTokenAddGoogle.ejs b/web/pages/blocks/loginTokenAddGoogle.ejs similarity index 100% rename from web/pages/loginTokenAddGoogle.ejs rename to web/pages/blocks/loginTokenAddGoogle.ejs diff --git a/web/pages/blocks/loginTokenAddLDAP.ejs b/web/pages/blocks/loginTokenAddLDAP.ejs new file mode 100644 index 00000000..abd182e7 --- /dev/null +++ b/web/pages/blocks/loginTokenAddLDAP.ejs @@ -0,0 +1,47 @@ +<% + details = $user.details + window.libURL = originalURL + global.s.checkCorrectPathEnding(config.webPaths.home) +%> + + + + + +<% + var drawBlock + var buildOptions +%> +
+<% + include fieldBuilders.ejs +%> +<% + drawBlock(define['LDAP'].blocks.LDAP) +%> +
+ diff --git a/web/pages/index.ejs b/web/pages/index.ejs index 9348cccd..f12d60b7 100644 --- a/web/pages/index.ejs +++ b/web/pages/index.ejs @@ -81,18 +81,11 @@ - <% if(config.showLoginSelector === true){ %> -
+
- <% switch(screen){ case'super': %> @@ -102,9 +95,6 @@ <% break; default: %> - <% if(config.productType==='Pro'){ %> - - <% } %> <% break; @@ -128,6 +118,14 @@ } %> <% } %> +
+ + +
@@ -233,7 +231,7 @@ $('[selector]').change(function(e){ diff --git a/web/pages/blocks/settings.ejs b/web/pages/blocks/settings.ejs index 0cb00319..39d1b9b7 100644 --- a/web/pages/blocks/settings.ejs +++ b/web/pages/blocks/settings.ejs @@ -30,224 +30,11 @@
<% - var buildOptions = function(field,possiblities){ - if(!field)console.error('field',field) - var fieldElement = '' - possiblities.forEach(function(option){ - if(option.optgroup){ - fieldElement += '' - fieldElement += buildOptions(field,option.optgroup) - fieldElement += '' - }else{ - var selected = '' - if(option.value === field.default){ - selected = 'selected' - } - fieldElement += '' - } - }) - return fieldElement - } - var drawBlock = function(monitorSettings){ - if(monitorSettings.evaluation && !eval(monitorSettings.evaluation)){ - return - } - var attributes = [] - var styles = [] - var sectionClass = [] - var headerTitle = monitorSettings.headerTitle || lang[monitorSettings.name] || monitorSettings.name - if(monitorSettings.hidden === true){ - styles.push('display:none') - } - if(monitorSettings.style){ - styles.push(monitorSettings.style) - } - if(monitorSettings.isSection === true){ - attributes.push('section') - } - if(monitorSettings.attribute){ - attributes.push(monitorSettings.attribute) - } - if(!monitorSettings.id){ - var userSettingsId = monitorSettings.name.replace(/[^a-zA-Z ]/g, '').replace(/[^a-zA-Z ]/g, '').replace(/ /g, '') - monitorSettings.id = userSettingsId - } - attributes.push(`id="${monitorSettings.id}"`) - if(monitorSettings.color){ - sectionClass.push(monitorSettings.color) - } - if(monitorSettings['section-class']){ - sectionClass.push(monitorSettings['section-class']) - } - if(monitorSettings.isAdvanced){ %> - - <% } - } + include fieldBuilders.ejs %> <% Object.keys(define['Account Settings'].blocks).forEach(function(blockKey){ var accountSettings = define['Account Settings'].blocks[blockKey] From 226c41c727c883cd588bdef602ee911cd0e338cd Mon Sep 17 00:00:00 2001 From: Moe Date: Wed, 7 Apr 2021 19:06:06 -0700 Subject: [PATCH 5/6] Fix backblaze init when disabled --- libs/uploaders/backblazeB2.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/uploaders/backblazeB2.js b/libs/uploaders/backblazeB2.js index b61cefdc..0ca101b5 100644 --- a/libs/uploaders/backblazeB2.js +++ b/libs/uploaders/backblazeB2.js @@ -33,7 +33,8 @@ module.exports = function(s,config,lang){ userDetails.bb_b2_applicationKey && userDetails.bb_b2_applicationKey !=='' && userDetails.bb_b2_bucket && - userDetails.bb_b2_bucket !== '' + userDetails.bb_b2_bucket !== '' && + userDetails.bb_b2_save === '1' ){ var B2 = require('backblaze-b2') if(!userDetails.bb_b2_dir || userDetails.bb_b2_dir === '/'){ From a127df5f5ae4c88ba3982e9fd6ddb767281877be Mon Sep 17 00:00:00 2001 From: Matt Evangelisti Date: Thu, 8 Apr 2021 02:12:39 +0000 Subject: [PATCH 6/6] Repair cert file copy: SSL_CONFIG points to ./ssl, not ./ssl/ssl --- Docker/init.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Docker/init.sh b/Docker/init.sh index 3ba8541b..d45d6f2c 100644 --- a/Docker/init.sh +++ b/Docker/init.sh @@ -8,7 +8,7 @@ sed -i "s/$OLD_SQL_USER_TAG/$NEW_SQL_USER_TAG/g" sql/framework1.sql if [ "$SSL_ENABLED" = "true" ]; then if [ -d /config/ssl ]; then echo "Using provided SSL Key" - cp -R /config/ssl ssl + cp -R /config/ssl ./ SSL_CONFIG='{"key":"./ssl/server.key","cert":"./ssl/server.cert"}' else echo "Making new SSL Key"