UNPKG

2.64 kBJavaScriptView Raw
1import { createSecureContext } from 'tls'
2import chalk from 'chalk'
3import createHandler from './serve-handler'
4import fs from 'fs'
5import http from 'http'
6import https from 'https'
7
8const HOST = '0.0.0.0'
9
10export default function serve(apps) {
11 const appsByRoot = {}
12 const roots = apps.map(app => {
13 const root = `${app.domain}${app.root}`
14 appsByRoot[root] = app
15 if (app.secure) {
16 app.secureContext = createSecureContext({
17 cert: fs.readFileSync(app.secure.cert),
18 key: fs.readFileSync(app.secure.key)
19 })
20 }
21 return root
22 })
23
24 const findApp = req => {
25 const fullUrl = `${req.headers.host}${req.url}`
26 const root = roots.filter(r => fullUrl.indexOf(r.replace(/\/$/, '')) === 0).sort()[0]
27 return appsByRoot[root] || apps[0]
28 }
29
30 let warnedAboutSecure = false
31
32 const SNICallback = (domain, cb) => {
33 try {
34 // any app on that domain will do as they should all have the same key/cert
35 const app = apps.find(a => a.domain === domain)
36
37 if (!app.secure && !warnedAboutSecure) {
38 warnedAboutSecure = true
39 setTimeout(() => warnedAboutSecure = false, 100)
40
41 console.log(chalk.red(`You tried to access ${domain} through https but we don't have its certificate and key.`),
42`Does the app's panels.config.js include a secure key like?:
43
44 secure: {
45 cert: '/path/to/file.cert',
46 key: '/path/to/file.key'
47 }
48
49If you don't care about https, you can always access http://${domain}`)
50 }
51
52 cb(null, app.secureContext)
53 } catch(err) {
54 console.log(chalk.red(domain), err)
55 }
56 }
57
58 const handler = (req, res) => {
59 const app = findApp(req)
60 app.handler(req, res, () => createHandler(app)(req, res))
61 }
62
63 const s = https.createServer({ SNICallback }, handler)
64 s.on('error', console.error.bind(console))
65 s.on('listening', () => {
66 const list = apps.filter(a => a.secure)
67 if (list.length) {
68 console.log(chalk.green('secure apps'))
69 console.log(list.map(app => ` https://${app.domain}${app.root}`).join('\n'))
70 }
71 })
72 s.listen(443, HOST)
73
74 const s2 = http.createServer((req, res) => {
75 const app = findApp(req)
76
77 if (app.secure) {
78 res.writeHead(302, { Location: `https://${req.headers.host}${app.root}` })
79 res.end()
80 } else {
81 handler(req, res)
82 }
83 })
84 s2.on('error', console.error.bind(console))
85 s2.on('listening', () => {
86 const list = apps.filter(a => !a.secure)
87
88 if (list.length) {
89 console.log(chalk.yellow('insecure apps'))
90 console.log(list.map(app => ` http://${app.domain}${app.root}`).join('\n'))
91 }
92 })
93 s2.listen(80, HOST)
94}