Commit ae53484a authored by NGPixel's avatar NGPixel

feat: admin ssl - renew cert + toggle redirection btn

parent 59a8e992
......@@ -73,7 +73,7 @@
"express": "4.17.1",
"express-brute": "1.0.1",
"express-session": "1.17.0",
"file-type": "13.1.0",
"file-type": "13.1.1",
"filesize": "6.0.1",
"fs-extra": "8.1.0",
"getos": "3.1.1",
......@@ -121,7 +121,7 @@
"node-2fa": "1.1.2",
"node-cache": "5.1.0",
"nodemailer": "6.4.2",
"objection": "1.6.11",
"objection": "2.1.2",
"passport": "0.4.1",
"passport-auth0": "1.3.1",
"passport-azure-ad": "4.2.1",
......@@ -158,7 +158,7 @@
"scim-query-filter-parser": "2.0.4",
"semver": "7.1.1",
"serve-favicon": "2.5.0",
"simple-git": "1.129.0",
"simple-git": "1.130.0",
"solr-node": "1.2.1",
"sqlite3": "4.1.1",
"ssh2": "0.8.7",
......@@ -188,7 +188,7 @@
"@babel/plugin-syntax-import-meta": "^7.8.3",
"@babel/polyfill": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"@mdi/font": "4.7.95",
"@mdi/font": "4.8.95",
"@panter/vue-i18next": "0.15.1",
"@requarks/ckeditor5": "12.4.0-wiki.14",
"@vue/babel-preset-app": "4.1.2",
......
......@@ -54,6 +54,8 @@ defaults:
securityHSTSDuration: 300
securityCSP: false
securityCSPDirectives: ''
server:
sslRedir: false
flags:
ldapdebug: false
sqllog: false
......
const express = require('express')
const router = express.Router()
const _ = require('lodash')
const qs = require('querystring')
/* global WIKI */
......@@ -22,4 +23,16 @@ router.get('/.well-known/acme-challenge/:token', (req, res, next) => {
}
})
/**
* Redirect to HTTPS if HTTP Redirection is enabled
*/
router.all('/*', (req, res, next) => {
if (WIKI.config.server.sslRedir && !req.secure && WIKI.servers.servers.https) {
let query = (!_.isEmpty(req.query)) ? `?${qs.stringify(req.query)}` : ``
return res.redirect(`https://${req.hostname}${req.originalUrl}${query}`)
} else {
next()
}
})
module.exports = router
......@@ -46,7 +46,7 @@ module.exports = {
})
this.servers.http.on('connection', conn => {
let connKey = `${conn.remoteAddress}:${conn.remotePort}`
let connKey = `http:${conn.remoteAddress}:${conn.remotePort}`
this.connections.set(connKey, conn)
conn.on('close', () => {
this.connections.delete(connKey)
......@@ -108,7 +108,7 @@ module.exports = {
})
this.servers.https.on('connection', conn => {
let connKey = `${conn.remoteAddress}:${conn.remotePort}`
let connKey = `https:${conn.remoteAddress}:${conn.remotePort}`
this.connections.set(connKey, conn)
conn.on('close', () => {
this.connections.delete(connKey)
......@@ -135,11 +135,17 @@ module.exports = {
/**
* Close all active connections
*/
closeConnections () {
for (const conn of this.connections.values()) {
closeConnections (mode = 'all') {
for (const [key, conn] of this.connections) {
if (mode !== `all` && key.indexOf(`${mode}:`) !== 0) {
continue
}
conn.destroy()
this.connections.delete(key)
}
if (mode === 'all') {
this.connections.clear()
}
this.connections.clear()
},
/**
* Stop all servers
......@@ -155,5 +161,29 @@ module.exports = {
this.servers.https = null
}
this.servers.graph = null
},
/**
* Restart Server
*/
async restartServer (srv = 'https') {
this.closeConnections(srv)
switch (srv) {
case 'http':
if (this.servers.http) {
await Promise.fromCallback(cb => { this.servers.http.close(cb) })
this.servers.http = null
}
this.startHTTP()
break
case 'https':
if (this.servers.https) {
await Promise.fromCallback(cb => { this.servers.https.close(cb) })
this.servers.https = null
}
this.startHTTPS()
break
default:
throw new Error('Cannot restart server: Invalid designation')
}
}
}
......@@ -220,6 +220,38 @@ module.exports = {
} catch (err) {
return graphHelper.generateError(err)
}
},
/**
* Set HTTPS Redirection State
*/
async setHTTPSRedirection (obj, args, context) {
_.set(WIKI.config, 'server.sslRedir', args.enabled)
await WIKI.configSvc.saveToDb(['server'])
return {
responseResult: graphHelper.generateSuccess('HTTP Redirection state set successfully.')
}
},
/**
* Renew SSL Certificate
*/
async renewHTTPSCertificate (obj, args, context) {
try {
if (!WIKI.config.ssl.enabled) {
throw new WIKI.Error.SystemSSLDisabled()
} else if (WIKI.config.ssl.provider !== `letsencrypt`) {
throw new WIKI.Error.SystemSSLRenewInvalidProvider()
} else if (!WIKI.servers.le) {
throw new WIKI.Error.SystemSSLLEUnavailable()
} else {
await WIKI.servers.le.requestCertificate()
await WIKI.servers.restartServer('https')
return {
responseResult: graphHelper.generateSuccess('SSL Certificate renewed successfully.')
}
}
} catch (err) {
return graphHelper.generateError(err)
}
}
},
SystemInfo: {
......@@ -266,6 +298,15 @@ module.exports = {
hostname () {
return os.hostname()
},
httpPort () {
return WIKI.servers.servers.http ? _.get(WIKI.servers.servers.http.address(), 'port', 0) : 0
},
httpRedirection () {
return _.get(WIKI.config, 'server.sslRedir', false)
},
httpsPort () {
return WIKI.servers.servers.https ? _.get(WIKI.servers.servers.https.address(), 'port', 0) : 0
},
latestVersion () {
return WIKI.system.updates.version
},
......@@ -293,6 +334,21 @@ module.exports = {
ramTotal () {
return filesize(os.totalmem())
},
sslDomain () {
return WIKI.config.ssl.enabled && WIKI.config.ssl.provider === `letsencrypt` ? WIKI.config.ssl.domain : null
},
sslExpirationDate () {
return WIKI.config.ssl.enabled && WIKI.config.ssl.provider === `letsencrypt` ? _.get(WIKI.config.letsencrypt, 'payload.expires', null) : null
},
sslProvider () {
return WIKI.config.ssl.enabled ? WIKI.config.ssl.provider : null
},
sslStatus () {
return 'OK'
},
sslSubscriberEmail () {
return WIKI.config.ssl.enabled && WIKI.config.ssl.provider === `letsencrypt` ? WIKI.config.ssl.subscriberEmail : null
},
telemetry () {
return WIKI.telemetry.enabled
},
......
......@@ -40,6 +40,12 @@ type SystemMutation {
mongoDbConnString: String!
groupMode: SystemImportUsersGroupMode!
): SystemImportUsersResponse @auth(requires: ["manage:system"])
setHTTPSRedirection(
enabled: Boolean!
): DefaultResponse @auth(requires: ["manage:system"])
renewHTTPSCertificate: DefaultResponse @auth(requires: ["manage:system"])
}
# -----------------------------------------------
......@@ -65,6 +71,9 @@ type SystemInfo {
dbVersion: String @auth(requires: ["manage:system"])
groupsTotal: Int @auth(requires: ["manage:system", "manage:navigation", "manage:groups", "write:groups", "manage:users", "write:users"])
hostname: String @auth(requires: ["manage:system"])
httpPort: Int @auth(requires: ["manage:system"])
httpRedirection: Boolean @auth(requires: ["manage:system"])
httpsPort: Int @auth(requires: ["manage:system"])
latestVersion: String @auth(requires: ["manage:system"])
latestVersionReleaseDate: Date @auth(requires: ["manage:system"])
nodeVersion: String @auth(requires: ["manage:system"])
......@@ -72,6 +81,11 @@ type SystemInfo {
pagesTotal: Int @auth(requires: ["manage:system", "manage:navigation", "manage:pages", "delete:pages"])
platform: String @auth(requires: ["manage:system"])
ramTotal: String @auth(requires: ["manage:system"])
sslDomain: String @auth(requires: ["manage:system"])
sslExpirationDate: Date @auth(requires: ["manage:system"])
sslProvider: String @auth(requires: ["manage:system"])
sslStatus: String @auth(requires: ["manage:system"])
sslSubscriberEmail: String @auth(requires: ["manage:system"])
telemetry: Boolean @auth(requires: ["manage:system"])
telemetryClientId: String @auth(requires: ["manage:system"])
upgradeCapable: Boolean @auth(requires: ["manage:system"])
......
......@@ -165,6 +165,22 @@ module.exports = {
message: 'An unexpected error occured during search operation.',
code: 4001
}),
SystemGenericError: CustomError('SystemGenericError', {
message: 'An unexpected error occured.',
code: 7001
}),
SystemSSLDisabled: CustomError('SystemSSLDisabled', {
message: 'SSL is not enabled.',
code: 7002
}),
SystemSSLLEUnavailable: CustomError('SystemSSLLEUnavailable', {
message: 'Let\'s Encrypt is not initialized.',
code: 7004
}),
SystemSSLRenewInvalidProvider: CustomError('SystemSSLRenewInvalidProvider', {
message: 'Current provider does not support SSL certificate renewal.',
code: 7003
}),
UserCreationFailed: CustomError('UserCreationFailed', {
message: 'An unexpected error occured during user creation.',
code: 1009
......
......@@ -59,10 +59,10 @@ module.exports = async () => {
}))
// ----------------------------------------
// Let's Encrypt Challenge
// SSL Handlers
// ----------------------------------------
app.use('/', ctrl.letsencrypt)
app.use('/', ctrl.ssl)
// ----------------------------------------
// Passport Authentication
......
This diff was suppressed by a .gitattributes entry.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment