huskee-install
Version:
Huskee server installer
134 lines (117 loc) • 4.35 kB
JavaScript
const https = require('https')
const http = require('http')
const fs = require('fs')
const tls = require('tls')
const routing = require('../lib/routing.compiled')
const path = require('path')
const hosts = require('../conf/hosts')
const hostsObject = hosts.map(h => {
const orig = h.originsWithAccess || []
h.originsWithAccess = orig.reduce((o, next) => ({
...o,
[next]: true
}), {})
return h
}).reduce((h, next) => ({
...h,
[next.host]: next
}), {})
const config = require('../conf/main')
const punycode = require('punycode')
require('./socketproxy')
const fsStatAsync = path => new Promise(resolve => {
fs.stat(path, (err, stats) => err ? resolve(0) : resolve(stats))
})
const secureContext = {}
const secureKeys = {}
const getSSLKeys = domain => ({
key: fs.readFileSync(`/etc/letsencrypt/live/${domain}/privkey.pem`, 'utf-8'),
cert: fs.readFileSync(`/etc/letsencrypt/live/${domain}/fullchain.pem`, 'utf-8'),
ca: fs.readFileSync(`/etc/letsencrypt/live/${domain}/chain.pem`, 'utf-8')
})
const createSSL = keys => tls.createSecureContext(keys)
hosts.forEach(async host => {
const key = host.host
const wwwPath = path.join(__dirname, `../www/${key}/`)
const apiPath = path.join(__dirname, `../dynamic/${key}`)
const www = await fsStatAsync(wwwPath)
if(!www) fs.mkdir(wwwPath, e => {e}) //TODO: add callback
const api = await fsStatAsync(apiPath)
if(!api) fs.mkdir(apiPath, e => {e}) //TODO: add callback
if(host.ssl === true) {
try{
secureKeys[key] = getSSLKeys(key)
secureContext[key] = createSSL(secureKeys[key])
}
catch(e) {
console.log(`No cert for the ${key} host`)
}
const { onload, host: hostname } = host
if(!onload) return
if(typeof onload === 'object' && onload.forEach) onload.forEach(loadPath => {
const path = `../dynamic/${hostname}/${loadPath}`
try {
var appToLoad = require(path)
}
catch(e) { return console.error(`ERROR: can't find ${loadPath} script in ${hostname} settings. Error: ${e}`) }
if(typeof appToLoad === 'function') {
try {
appToLoad()
}
catch(e) { return console.error(`ERROR: your ${loadPath} script in ${hostname} settings seems to be broken`) }
}
})
}
})
const options = {
SNICallback: (domain, cb) => cb(null, secureContext[domain])
}
const processConnection = (req, res) => {
res.setHeader('Server', 'Huskee')
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTION, DELETE, PUT')
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type')
res.setHeader('Access-Control-Allow-Credentials', true)
const host = punycode.toUnicode(req.headers.host || '')
const { originsWithAccess = {} } = hostsObject[host] || {}
const { origin = '' } = req.headers
const testOrigin = origin.includes(':') ? origin.split('://')[1] : origin
if(originsWithAccess[testOrigin]) res.setHeader('Access-Control-Allow-Origin', origin)
let length = 0
let dataString = ''
req.on('data', chunk => {
dataString = dataString.concat(decodeURI(chunk))
length += Buffer.byteLength(chunk, 'utf-8')
if(length/1024 > 10*1024) {
res.destroy()
}
})
req.on('end', () => {
new routing.Connection(req, res, dataString)
})
}
https.createServer(options, (req, res) => {
const host = req.headers.host
const encryption = secureKeys[host]
req.encryption = encryption
processConnection(req, res)
}).listen(443)
http.createServer((req, res) => {
const host = req.headers.host
const ourHost = hosts.find(h => h.host === host)
const { ssl } = ourHost ? ourHost : {}
if(ssl) {
res.writeHead(301, { 'Location': 'https://' + req.headers.host + req.url })
return res.end()
}
processConnection(req, res)
}).listen(config.port /*'forgetable.ru', null, () => {
try {
console.log('Old User ID: ' + process.getuid() + ', Old Group ID: ' + process.getgid())
process.setgid('users')
process.setuid('lena')
console.log('New User ID: ' + process.getuid() + ', New Group ID: ' + process.getgid())
} catch (err) {
console.log('Cowardly refusing to keep the process alive as root.')
process.exit(1)
}
}*/)