From 43048c6d121e4a25c48635533b1aeecf291d8f1d Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 28 Feb 2019 14:34:54 -0600 Subject: [PATCH] Force certificates --- packages/app/browser/src/app.html | 4 +-- packages/server/src/modules.ts | 3 +- packages/server/src/server.ts | 50 +++++++++++++++++++++++-------- 3 files changed, 42 insertions(+), 15 deletions(-) diff --git a/packages/app/browser/src/app.html b/packages/app/browser/src/app.html index a47b6078..6613918a 100644 --- a/packages/app/browser/src/app.html +++ b/packages/app/browser/src/app.html @@ -3,14 +3,14 @@ - Coder + Authenticate: code-server
<- Back
- +

code-server

Enter server password

diff --git a/packages/server/src/modules.ts b/packages/server/src/modules.ts index b87b2595..1c6d6268 100644 --- a/packages/server/src/modules.ts +++ b/packages/server/src/modules.ts @@ -1,5 +1,6 @@ import * as fs from "fs"; import * as path from "path"; +import * as os from "os"; import { isCli, buildDir } from "./constants"; declare var __non_webpack_require__: typeof require; @@ -19,7 +20,7 @@ export const setup = (dataDirectory: string): void => { } return currentDir; - }); // Might need path.sep here for linux. Having it for windows causes an error because \C:\Users ... + }, os.platform() === "win32" ? undefined! : path.sep); // Might need path.sep here for linux. Having it for windows causes an error because \C:\Users ... const unpackModule = (moduleName: string): void => { const memFile = path.join(isCli ? buildDir! : path.join(__dirname, ".."), "build/dependencies", moduleName); diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 97065fdc..bd7134c0 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -86,24 +86,46 @@ export const createApp = async (options: CreateAppOptions): Promise<{ options.registerMiddleware(app); } - const certs = await new Promise((res, rej): void => { - pem.createCertificate({ - selfSigned: true, - }, (err, result) => { - if (err) { - rej(err); + interface CertificateInfo { + readonly key: string; + // tslint:disable-next-line:no-any + readonly cert: any; + } - return; + const certs = await new Promise(async (resolve, reject): Promise => { + const selfSignedKeyPath = path.join(options.serverOptions!.dataDirectory, "self-signed.key"); + const selfSignedCertPath = path.join(options.serverOptions!.dataDirectory, "self-signed.cert"); + + if (!fs.existsSync(selfSignedKeyPath) || !fs.existsSync(selfSignedCertPath)) { + try { + const certs = await new Promise((res, rej): void => { + pem.createCertificate({ + selfSigned: true, + }, (err, result) => { + if (err) { + rej(err); + + return; + } + + res(result); + }); + }); + + fs.writeFileSync(selfSignedKeyPath, certs.serviceKey); + fs.writeFileSync(selfSignedCertPath, certs.certificate); + } catch (ex) { + return reject(ex); } + } - res(result); + resolve({ + cert: fs.readFileSync(selfSignedCertPath).toString(), + key: fs.readFileSync(selfSignedKeyPath).toString(), }); }); - const server = httpolyglot.createServer({ - key: certs.serviceKey, - cert: certs.certificate, - }, app) as http.Server; + const server = httpolyglot.createServer(options.httpsOptions || certs, app) as http.Server; const wss = new ws.Server({ server }); wss.shouldHandle = (req): boolean => { @@ -161,6 +183,10 @@ export const createApp = async (options: CreateAppOptions): Promise<{ const authStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/auth")); const unauthStaticFunc = expressStaticGzip(path.join(baseDir, "build/web/unauth")); app.use((req, res, next) => { + if (!isEncrypted(req.socket)) { + return res.redirect(301, `https://${req.headers.host!}${req.path}`); + } + if (isAuthed(req)) { // We can serve the actual VSCode bin authStaticFunc(req, res, next);